Глава 15. Механизмы обмена данными

15.1. Цели и задачи

15.1.1. Общая информация

Механизмы обмена данными ‑ это набор средств системы «1С:Предприятие», предназначенных для организации обмена данными между различными информационными базами, а также информационными базами и внешними программными системами. Механизмы обмена данными могут быть условно разделены на два уровня:

● универсальные механизмы обмена данными,

● распределенные информационные базы.

15.1.2. Универсальные механизмы обмена данными

Универсальные механизмы обмена данными могут использоваться как вместе, так и по отдельности, в различных комбинациях, для организации обмена данными информационных баз системы «1С:Предприятие» с различными программными системами. В качестве программных систем, с которыми организуется обмен, могут выступать другие информационные базы системы «1С:Предприятие». При этом обменивающиеся между собой информационные базы могут в общем случае иметь разные конфигурации.

Кроме того, универсальные механизмы обмена данными могут использоваться для организации обмена с программами, не основанными на системе «1С:Предприятие». Этому способствуют следующие факторы:

● формат обмена данными основан на языке XML, являющемся на сегодняшний день общепринятым средством представления данных;

● средства обмена данными, благодаря своей модульной организации и высокой гибкости, могут быть использованы для организации разнообразных схем обмена данными;

● протоколы, предлагаемые механизмами обмена данными, несложны и могут быть воспроизведены во внешних программных системах.

15.1.3. Распределенные информационные базы

Распределенная информационная база представляет собой иерархическую структуру, состоящую из отдельных информационных баз системы «1С:Предприятие» ‑ узлов распределенной информационной базы, между которыми организован обмен данными с целью синхронизации конфигурации и данных.

Механизмы управления распределенными информационными базами базируются на универсальных механизмах обмена данными, но содержат некоторые дополнительные возможности, недоступные через универсальные механизмы.

Главное отличие распределенных информационных баз от универсальных механизмов обмена данными заключается в том, что универсальные механизмы обмена данными позволяют выстраивать достаточно произвольные схемы обмена данными, в то время как распределенные информационные базы имеют более узкую специализацию, а также выполняют передачу изменений конфигурации в подчиненные узлы.

15.2. Универсальные механизмы обмена данными

15.2.1. Общая информация

К универсальным механизмам обмена данными могут быть отнесены:

● средства чтения и записи документов XML,

● XML-сериализация,

● планы обмена.

15.2.2. Средства чтения и записи документов XML

Предполагается, что участники обмена данными обмениваются сообщениями в формате XML. Таким образом, средства чтения и записи документов XML образуют базовый уровень обмена данными.

Средства чтения и записи документов XML обеспечивают работу с документами XML в самом общем виде. Данный набор средств не определяет способов представления данных системы «1С:Предприятие» в формате XML.

К средствам чтения и записи документов XML, предоставляемым системой «1С:Предприятие», относятся объекты: ЧтениеXML, ЗаписьXML и ПреобразованиеXSL. Также платформа предоставляет возможность работать с XML-данными в формате FastInfoset, для чего существуют объекты ЧтениеFastInfoset и ЗаписьFastInfoset.

15.2.3. XML-сериализация

Основная задача XML-сериализации ‑ поддержка чтения/записи объектов данных системы «1С:Предприятие» в/из XML.

Базовые средства чтения и записи документов XML не предоставляют достаточной основы для решения данной задачи. Они не определяют форматов представления данных системы «1С:Предприятие» в XML и не предоставляют средств для чтения/записи объектов данных в/из XML в принятом формате как единого целого.

15.2.3.1. Представление данных в XML-сериализации

В конечном счете каждый объект данных системы «1С:Предприятие» представляется как элемент XML, содержащий значение объекта данных.

С точки зрения представления в XML типы значений делятся на простые и сложные.

К простым типам данных относятся типы, значения которых представляются подсистемой XML-сериализации в виде элементов XML только с текстовым содержимым.

Значения сложных типов представляются в виде элементов XML, содержащих вложенные элементы.

Каждому из типов данных системы «1С:Предприятие», значения которых могут быть представлены в XML, ставится в соответствие тип данных XML.

Каждый тип данных XML характеризуется именем типа и пространством имен, к которому относится тип.

Тип данных XML может быть следующим:

● одним из типов, определенных в документе XML Schema Part 2: Datatypes консорциума W3C (пространство имен ‑ http://www.w3.org/2001/XMLSchema);

● предопределенным типом системы «1С:Предприятие» (пространство имен ‑ http://v8.1c.ru/data);

● типом, производным от метаданных конфигурации системы «1С:Предприятие» (не относится ни к какому пространству имен).

В представлении объекта данных в XML тип данных XML может быть задан в явном виде. Для задания типа данных XML элемент XML, содержащий представление значения, должен содержать атрибут type, относящийся к пространству имен http://www.w3.org/2001/XMLSchema-instance, значение которого содержит тип данных XML.

Другим возможным способом задания типа данных XML является имя корневого элемента XML, содержащего представление значения. Имя корневого элемента, представляющего объект данных, жестко не специфицируется и может быть произвольным. Однако если при записи значения в XML имя корневого элемента не задано, то оно будет установлено в соответствии с типом записываемого значения. При чтении данных из XML тип значения, если он не задан в атрибуте type, может быть установлен по имени корневого элемента.

При рассмотрении примеров представления различных значений в XML и при дальнейшем изложении будем исходить из предположения, что определены следующие соответствия пространств имен:

Копировать в буфер обмена
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema instance"
xmlns:v8="http://v8.1c.ru/data"
15.2.3.1.1. Представление значений простых типов в XML

К простым типам с точки зрения представления в XML относятся следующие типы системы «1С:Предприятие»:

Число;

Строка;

Дата;

Булево;

ДвоичныеДанные;

NULL;

УникальныйИдентификатор;

ХранилищеЗначения;

● все ссылки на объекты базы данных;

● ссылки на перечисления, определяемые в метаданных.

Число

Описание:

Типу Число соответствует тип данных XML decimal из пространства имен http://www.w3.org/2001/XMLSchema.

Правила представления значений данного типа определены в документе XML Schema Part 2: Datatypes.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<decimal>45684.087</decimal>
<!-- Явно задано имя корневого элемента XML -->
<Amount>523</Amount>
<!-- Явно указан тип данных XML -->
<Data xsi:type="xsd:decimal">64793.01</Data>

Строка

Описание:

Типу Строка соответствует тип данных string из пространства имен http://www.w3.org/2001/XMLSchema. Строка записывается в XML как есть.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<string>Это такая строка</string>
<!-- Явно задано имя корневого элемента XML -->
<Name>Иванов</Name>
<!-- Явно указан тип данных XML -->
<Data xsi:type="xsd:string">Это такая строка</Data>

Дата

Описание:

Значения типа Дата представляются в виде YYYY-MM-DDTHH:MM:SS, где:

YYYY ‑ год, представленный в виде четырех цифр;

MM ‑ месяц, представленный двумя цифрами;

DD ‑ день месяца двумя цифрами;

T ‑ латинская буква T;

HH ‑ час суток;

MM ‑ минута;

SS ‑ секунда.

Такой формат даты определен как допустимый в документе XML Schema Part 2: Datatypes.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<dateTime>2008-11-21T12:00:00</dateTime>
<!-- Явно задано имя корневого элемента XML -->
<Started>2001-10-30T19:00:00</Started>
<!-- Явно указан тип данных XML -->
<Data xsi:type="xsd:dateTime">1980-08-25T10:00:00</Data>

Булево

Описание:

Типу Булево соответствует тип данных boolean из пространства имен http://www.w3.org/2001/XMLSchema.

Значение Ложь представляется строкой false, а значение Истина ‑ строкой true. Такой формат предусмотрен в документе XML Schema Part 2: Datatypes.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<boolean>false</boolean>
<!-- Явно задано имя корневого элемента XML -->
<Posted>true</Posted>
<!-- Явно указан тип данных XML -->
<Data xsi:type="xsd:boolean">true</Data>

ДвоичныеДанные

Описание:

Типу ДвоичныеДанные соответствует тип данных XML base64Binary из пространства имен http://www.w3.org/2001/XMLSchema.

Значения данного типа представляются как двоичные данные, закодированные с использованием алгоритма Base64, описанного в RFC 2045 (https://datatracker.ietf.org/doc/html/rfc2045.html).

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<base64Binary>YWJjZGVm</base64Binary>
<!-- Явно задано имя корневого элемента XML -->
<BinaryData>YWJjZGVm</BinaryData>
<!-- Явно указан тип данных XML -->
<Data xsi:type="xsd:base64Binary">YWJjZGVm</Data>

NULL

Описание:

Типу NULL соответствует тип данных XML Null из пространства имен http://v8.1c.ru/data. Данный тип имеет одно-единственное значение, которое представляется пустой строкой.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<v8:Null/>
<!-- Явно задано имя корневого элемента XML -->
<Selected/>
<!-- Явно указан тип данных XML -->
<Data xsi:type="v8:Null"/>

УникальныйИдентификатор

Описание:

Типу УникальныйИдентификатор соответствует тип данных XML UUID из пространства имен http://v8.1c.ru/data.

Значения данного типа представляются в XML в соответствии с общепринятой практикой и стандартами (ISO-11578, DCE 1.1: Remote Procedure Call ‑ Universal Unique Identifier).

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<v8:UUID>3294be0f-c039-41a9-bd65-596da0dcfe68</v8:UUID>
<!-- Явно задано имя корневого элемента XML -->
<Id>da035e32-3f7a-4d87-41a9-accf7db8cb4b</Id>
<!-- Явно указан тип данных XML-->
<Data xsi:type="v8:UUID">08839b0b-5ec3-4a53-a9f5-173312316919</Data>

ХранилищеЗначения

Описание:

Типу ХранилищеЗначения соответствует тип данных XML ValueStorage из пространства имен http://v8.1c.ru/data.

Значения данного типа представляются в XML как данные ХранилищеЗначения, сохраненные в файл, а затем закодированные с использованием алгоритма Base64.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<v8:ValueStorage>AQEOAAAAAAAAAO+7v3siUyIsIjHQoSJ9</v8:ValueStorage>
<!-- Явно задано имя корневого элемента XML -->
<Data>AQEOAAAAAAAAAO+7v3siUyIsIjHQoSJ9</Data>
<!-- Явно указан тип данных XML -->
<Data xsi:type="v8:ValueStorage">AQEOAAAAAAAAAO+7v3siUyIsIjHQoSJ9</Data>

Ссылки на объекты базы данных

Описание:

Каждому из типов ссылок на объекты базы данных соответствует свой собственный тип данных XML. Имя типа данных XML для ссылок на объекты базы данных соответствует англоязычному имени типа значения ссылки системы «1С:Предприятие».

Так, например, для справочника Валюты англоязычное имя типа ссылки будет выглядеть как CatalogRef.Валюты. Так же будет выглядеть и имя типа данных XML.

Типы данных XML для ссылок на объекты базы данных не относятся ни к какому пространству имен.

Значения ссылок представляются в XML как значения типа УникальныйИдентификатор, полученные из ссылок.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<CatalogRef.Банки>911b5b8b-11f5-4993-9673-2c9a7a8995d5</CatalogRef.Банки >
<!-- Явно задано имя корневого элемента XML -->
<Ref>911b5b8b-11f5-4993-9673-2c9a7a8995d5</Ref>
<!-- Явно указан тип данных XML -->
<Data xsi:type="CatalogRef.Банки">911b5b8b-11f5-4993-9673-2c9a7a8995d5</Data>

Ссылки на перечисления, определяемые в метаданных

Описание:

Каждому из типов ссылок на значения перечислений, определенных в конфигурации, соответствует свой собственный тип данных XML. Имя типа данных XML для ссылок на значения перечисления соответствует англоязычному имени типа системы «1С:Предприятие».

Так, например, для перечисления ВидыАдресов англоязычное имя типа ссылки на значение будет выглядеть как EnumRef.ВидыАдресов. Так же будет выглядеть и имя типа данных XML.

Типы данных XML для ссылок на значения перечислений не относятся ни к какому пространству имен. В XML ссылки на значения перечислений представляются в виде имени соответствующего значения перечисления.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<EnumRef.ВидыАдресов>Юридический</EnumRef.ВидыАдресов>
<!-- Явно задано имя корневого элемента XML -->
<Ref>Юридический</Ref>
<!-- Явно указан тип данных XML -->
<Data xsi:type="EnumRef.ВидыАдресов">Физический</Data>
15.2.3.1.2. Представление значений сложных типов в XML

К сложным типам, значения которых могут быть представлены в XML, относятся следующие типы системы «1С:Предприятие»:

Тип;

ОписаниеТипов;

КонстантаМенеджерЗначения.<Имя константы>;

● все объекты базы данных;

● наборы записей регистров, последовательностей, перерасчетов;

УдалениеОбъекта.

Тип

Описание:

Типу Тип соответствует тип данных XML Type из пространства имен http://v8.1c.ru/data. Элемент XML, представляющий значение данного типа, содержит текст, в котором записано имя типа XML, соответствующего типу данных системы «1С:Предприятие».

На первый взгляд тип Тип относится не к сложным, а к простым типам данных, так как элемент, представляющий значение данного типа, не содержит вложенных элементов. Однако это не так. Вложенных элементов действительно нет. Но при этом текст элемента, содержащий имя типа данных XML, содержит префикс пространства имен типа, который должен быть определен в данном элементе или одном из родительских элементов, что делает текст элемента не вполне самодостаточным. Поэтому данный тип не отнесен к простым типам.

Пример:

Копировать в буфер обмена
<!-- Не задано явно имя корневого элемента -->
<v8:Type>v8:ValueStorage</v8:Type>
<!-- Явно задано имя корневого элемента XML -->
<Tp>xsd:string</Tp>
<!-- Явно указан тип данных XML -->
<Data xsi:type="v8:Type">v8:ValueStorage<Data>

ОписаниеТипов

Описание:

Типу ОписаниеТипов соответствует тип данных XML TypeDescription из пространства имен http://v8.1c.ru/data. Корневой элемент, представляющий значение типа ОписаниеТипов, включает в себя ряд вложенных элементов, каждый из которых содержит некоторую составляющую часть описания типов.

Вложенный элемент Types из пространства имен http://v8.1c.ru/data содержит представления отдельных типов, входящих в описание типов. Элемент с именем NumberQualifiers из пространства имен http://v8.1c.ru/data содержит квалификаторы числового значения. А элементы с именами StringQualifiers и DateQualifiers из того же пространства имен содержат квалификаторы строки и даты соответственно.

Пример:

Копировать в буфер обмена
<v8:TypeDescription>
    <v8:Types>
   <v8:Type>v8:UUID</v8:Type>
   <v8:Type>CatalogRef.Банки</v8:Type>
   <v8:Type>xsd:boolean</v8:Type>
   <v8:Type>xsd:decimal</v8:Type>
    </v8:Types>
    <v8:NumberQualifiers>
   <v8:Digits>10</v8:Digits>
   <v8:FractionDigits>2</v8:FractionDigits>
   <v8:AllowedSign>Any</v8:AllowedSign>
    </v8:NumberQualifiers>
    <v8:StringQualifiers>
   <v8:Length>30</v8:Length>
   <v8:AllowedLength>Variable</v8:AllowedLength>
    </v8:StringQualifiers>
    <v8:DateQualifiers>
   <v8:DateFractions>Date</v8:DateFractions>
    </v8:DateQualifiers>
</v8:TypeDescription>

КонстантаМенеджерЗначения.<Имя константы>

Описание:

Каждому из типов КонстантаМенеджерЗначения.<Имя константы> соответствует тип данных XML ConstantValueManager.<Имя константы>, не относящийся ни к какому пространству имен.

Пример:

Копировать в буфер обмена
<ConstantValueManager.НазваниеОрганизации>
<Value>ООО "Мебиус"</Value>
</ConstantValueManager.НазваниеОрганизации>

Объекты базы данных

Описание:

Объекты базы данных представляются в XML как совокупность значений реквизитов и табличных частей. Имя типа данных XML, соответствующего объекту базы данных, определяется как англоязычное имя типа значения системы «1С:Предприятие». Типы данных XML для объектов базы данных не относятся ни к какому пространству имен. Состав элементов XML, вложенных в корневой элемент, определяется типом объекта, а также составом реквизитов и табличных частей.

Каждый из реквизитов представляется элементом XML, имя которого соответствует имени реквизита. Если тип значения реквизита не может быть однозначно определен из метаданных, то элемент XML, представляющий реквизит, содержит атрибут xsi:type, в котором указан тип значения XML.

Каждая из табличных частей представляется элементом XML, имя которого совпадает с именем табличной части.

Каждая из строк табличной части представляется элементом XML с именем Row. Реквизиты табличной части представлены элементами XML, вложенными в элемент Row.

Пример:

Представление в XML объекта типа Документ.ЗаказПокупателя:

Копировать в буфер обмена
<DocumentObject.ЗаказПокупателя>
    <Ref>8d106783-9726-11d7-9334-0050ba8480bd</Ref>
    <DeletionMark>false</DeletionMark>
    <Date>2008-04-15T12:00:00</Date>
    <Number>00000006</Number>
    <Posted>true</Posted>
    <ПодразделениеКомпании>317f130d-5a08-11d7-9324-0050ba8480bd</ПодразделениеКомпании>
    <СтруктурнаяЕдиница xsi:type="CatalogRef.КассыКомпании">317f12f4-5a08-11d7-9324-0050ba8480bd</СтруктурнаяЕдиница>
    <Контрагент>12952ac7-5a08-11d7-9324-0050ba8480bd</Контрагент>
    <ЮрФизЛицоКонтрагента xsi:type="CatalogRef.ЮридическиеЛица">0aadfe81-5a08-11d7-9324-0050ba8480bd</ЮрФизЛицоКонтрагента>
    <ВалютаДокумента>029156b4-5a08-11d7-9324-0050ba8480bd</ВалютаДокумента>
    <КурсДокумента>1</КурсДокумента>
    <УчитыватьНДС>true</УчитыватьНДС>
    <УчитыватьНП>false</УчитыватьНП>
    <СуммаВключаетНДС>false</СуммаВключаетНДС>
    <СуммаВключаетНП>false</СуммаВключаетНП>
    <Комментарий/>
    <СуммаДокумента>44077.14</СуммаДокумента>
    <ВидОперации>СчетНаОплату</ВидОперации>
    <ДоговорВзаиморасчетов>b0401f23-6e84-11d7-932c-0050ba8480bd</ДоговорВзаиморасчетов>
    <СкладКомпании>317f1317-5a08-11d7-9324-0050ba8480bd</СкладКомпании>
    <ТипЦен>317f1311-5a08-11d7-9324-0050ba8480bd</ТипЦен>
    <ДатаОплаты>2008-04-15T00:00:00</ДатаОплаты>
    <АвтоРезервирование>false</АвтоРезервирование>
    <АвтоРазмещение>false</АвтоРазмещение>
    <КурсВзаиморасчетов>33.4209</КурсВзаиморасчетов>
    <ТипСкидкиНаценки>00000000-0000-0000-0000-000000000000</ТипСкидкиНаценки>
    <Организация>317f1308-5a08-11d7-9324-0050ba8480bd</Организация>
    <ДатаОтгрузки>2008-04-15T00:00:00</ДатаОтгрузки>
    <Ответственный>4ff40e0b-5ac5-11d7-9325-0050ba8480bd</Ответственный>
    <КратностьДокумента>1</КратностьДокумента>
    <КратностьВзаиморасчетов>1</КратностьВзаиморасчетов>
    <Товары>
   <Row>
    <Номенклатура>297c6534-5a08-11d7-9324-0050ba8480bd</Номенклатура>
    <ЕдиницаИзмерения>297c6535-5a08-11d7-9324-0050ba8480bd</ЕдиницаИзмерения>
    <Цена>4537.56</Цена>
    <Сумма>13612.68</Сумма>
    <СтавкаНДС>НДС20</СтавкаНДС>
    <СуммаНДС>2722.54</СуммаНДС>
    <СтавкаНП>1ac73736-5a08-11d7-9324-0050ba8480bd</СтавкаНП>
    <СуммаНП>0</СуммаНП>
    <ХарактеристикаНоменклатуры>00000000-0000-0000-0000-000000000000</ХарактеристикаНоменклатуры>
    <Размещение xsi:nil="true"/>
    <Коэффициент>1</Коэффициент>
    <Количество>3</Количество>
    <ПроцентСкидкиНаценки>0</ПроцентСкидкиНаценки>
   </Row>
   <Row>
    <Номенклатура>317f12d8-5a08-11d7-9324-0050ba8480bd</Номенклатура>
    <ЕдиницаИзмерения>317f12d9-5a08-11d7-9324-0050ba8480bd</ЕдиницаИзмерения>
    <Цена>4915.55</Цена>
    <Сумма>19662.2</Сумма>
    <СтавкаНДС>НДС20</СтавкаНДС>
    <СуммаНДС>3932.44</СуммаНДС>
    <СтавкаНП>1ac73736-5a08-11d7-9324-0050ba8480bd</СтавкаНП>
    <СуммаНП>0</СуммаНП>
    <ХарактеристикаНоменклатуры>00000000-0000-0000-0000-000000000000</ХарактеристикаНоменклатуры>
    <Размещение xsi:nil="true"/>
    <Коэффициент>1</Коэффициент>
    <Количество>4</Количество>
    <ПроцентСкидкиНаценки>0</ПроцентСкидкиНаценки>
   </Row>
    </Товары>
    <ВозвратнаяТара/>
</DocumentObject.ЗаказПокупателя>

Примечание. В используемом примере, а также в других примерах данной главы присутствуют длинные строки (например, <ЕдиницаИзмерения>317f12d9-5a08-11d7-9324-0050ba8480bd</ЕдиницаИзмерения>). В связи с ограничением, накладываемым форматом книги, такие строки приводятся с переносом на следующую строку (или строки) текста. Реально такие строки записываются в модуле в одну строку.

Набор записей

Описание:

Представление в XML набора записей включает отбор, по которому получен набор записей, и сами записи, входящие в отбор. Значения отбора представлены во вложенном элементе XML с именем Filter, не относящимся ни к какому пространству имен. А все записи, составляющие набор записей, представлены во вложенном элементе с именем Records, также не относящимся ни к какому пространству имен. Записи представлены элементами XML с именем Record, вложенными в элемент Records. Имя элемента Record также не относится ни к какому пространству имен.

Пример:

Представление в XML набора записей регистра накопления ОстаткиТоваровКомпании:

Копировать в буфер обмена
<AccumulationRegisterRecordSet.ОстаткиТоваровКомпании>
    <Filter>
   <Recorder xsi:type="DocumentRef.РеализацияТоваров">1725f36e-6f35-11d7-932d-0050ba8480bd</Recorder>
    </Filter>
    <Records>
   <Record>
       <Recorder xsi:type="DocumentRef.РеализацияТоваров">1725f36e-6f35-11d7-932d-0050ba8480bd</Recorder>
    <Period>2008-04-13T17:45:39</Period>
    <MovementType>Expense</MovementType>
    <Active>true</Active>
    <Номенклатура>297c6556-5a08-11d7-9324-0050ba8480bd</Номенклатура>
    <СкладКомпании>317f1317-5a08-11d7-9324-0050ba8480bd</СкладКомпании>
    <Заказ xsi:nil="true"/>
    <ЦенаВРознице>0</ЦенаВРознице>
    <ХарактеристикаНоменклатуры>00000000-0000-0000-0000-000000000000</ХарактеристикаНоменклатуры>
    <Количество>2</Количество>
    <ПодразделениеКомпании>317f130d-5a08-11d7-9324-0050ba8480bd</ПодразделениеКомпании>
   </Record>
   <Record>
    <Recorder xsi:type="DocumentRef.РеализацияТоваров">1725f36e-6f35-11d7-932d-0050ba8480bd</Recorder>
    <Period>2008-04-13T17:45:39</Period>
    <MovementType>Expense</MovementType>
    <Active>true</Active>
    <Номенклатура>297c6558-5a08-11d7-9324-0050ba8480bd</Номенклатура>
    <СкладКомпании>317f1317-5a08-11d7-9324-0050ba8480bd</СкладКомпании>
    <Заказ xsi:nil="true"/>
    <ЦенаВРознице>0</ЦенаВРознице>
    <ХарактеристикаНоменклатуры>ac47d77e-5ec7-11d7-9329-0050ba8480bd</ХарактеристикаНоменклатуры>
    <Количество>2</Количество>
    <ПодразделениеКомпании>317f130d-5a08-11d7-9324-0050ba8480bd</ПодразделениеКомпании>
   </Record>
    </Records>
</AccumulationRegisterRecordSet.ОстаткиТоваровКомпании>

УдалениеОбъекта

Описание:

Типу УдалениеОбъекта соответствует тип данных XML ObjectDeletion из пространства имен http://v8.1c.ru/data. Корневой элемент XML-представления значения типа УдалениеОбъекта содержит один вложенный элемент с именем Ref из пространства имен http://v8.1c.ru/data, в котором находится представление ссылки на объект базы данных.

Пример:

Представление в XML объекта типа УдалениеОбъекта:

Копировать в буфер обмена
<v8:ObjectDeletion xmlns="http://v8.1c.ru/data">
<v8:Ref xsi:type="CatalogRef.Банки">
60c5cec3-7f6f-4ec3-9620-e757fe3614ca</v8:Ref>
</v8:ObjectDeletion>

15.2.3.2. Доступ к средствам XML-сериализации из встроенного языка

15.2.3.2.1. Простые значения

Для работы с XML-представлениями значений простых типов предназначены два метода глобального контекста ‑ XMLСтрока() и XMLЗначение().

Метод XMLСтрока() имеет единственный параметр ‑ значение, для которого нужно получить XML-представление. Это значение должно относиться к типу, являющемуся простым с точки зрения XML-сериализации. В противном случае будет вызвано исключение. При нормальном завершении функция возвращает строку, которая может быть использована как текст элемента XML, представляющего значение простого типа.

Метод XMLЗначение() выполняет противоположную задачу. У этого метода два параметра:

● тип значения, которое нужно получить из строки;

● сама строка.

15.2.3.2.2. Преобразование типов

Для преобразования типа данных системы «1С:Предприятие» в тип данных XML и наоборот предназначены методы XMLТип() и ИзXMLТипа(). Метод XMLТип() имеет один параметр ‑ тип, для которого нужно получить соответствующий тип данных XML. Если соответствующий тип данных XML определен, то метод возвращает значение типа ТипДанныхXML. Если же соответствующего типа данных XML нет, то метод возвращает значение Неопределено.

Метод ИзXMLТипа() имеет два варианта вызова. В первом варианте метод имеет единственный параметр типа ТипДанныхXML. Во втором варианте параметра два: имя типа XML и пространство имен. В обоих случаях метод возвращает соответствующий типу данных XML тип данных системы «1С:Предприятие», если таковой имеется, или Неопределено в противном случае.

15.2.3.2.3. Запись в XML-файл

Метод ЗаписатьXML() имеет два обязательных параметра. Первый параметр ‑ это объект типа ЗаписьXML, через который осуществляется запись XML; а второй ‑ значение, которое должно быть записано в XML. Если в качестве значения, помещаемого в XML, будет передано значение типа, который не может быть представлен в XML, то будет вызвано исключение.

Значение, которое записывается в XML, может представлять собой одно из двух больших «классов» объектов:

1. Конкретный элемент какого-либо типа, который поддерживает сериализацию в XML. Это может быть, например, элемент справочника, константа или конкретный документ. В этом случае выполняется запись единственного, указанного в качестве значения параметра Значение, элемента. Примером такой записи будет следующий код:

Копировать в буфер обмена
XML.ЗаписатьНачалоЭлемента("object");
ЗаписатьXML(XML, КлючевойТовар.ПолучитьОбъект());
XML.ЗаписатьКонецЭлемента();

В приведенном примере будет выполнена XML-сериализация объекта, ссылка на который расположена в переменной КлючевойТовар.

2. Один из следующих объектов метаданных: бизнес-процесс, документ, задача, константа, план видов расчета, план видов характеристик, план счетов, последовательность, регистр бухгалтерии, регистр накопления, регистр расчета, регистр сведений (в том числе независимый), справочник. В этом случае в XML будут записан все данные указанного объекта метаданных, которые доступны текущему пользователю. Примером такой записи будет следующий код:

Копировать в буфер обмена
XML.ЗаписатьНачалоЭлемента("meta");
ЗаписатьXML(XML, Метаданные.Справочники.Товары);
XML.ЗаписатьКонецЭлемента();

В данном примере в XML-файл будут записаны все элементы справочника Товары, которые доступны пользователю, от имени которого выполняется приведенный пример.

Необязательные параметры образуют три различных варианта вызова метода. В простейшем случае параметра три, и в качестве третьего параметра указывается значение перечисления НазначениеТипаXML, определяющее необходимость явного указания типа данных XML в атрибуте xsi:type корневого элемента XML.

У следующего варианта вызова в качестве третьего параметра используется строковое значение, указывается имя корневого элемента XML. При этом подразумевается, что пространство имен не определено. Четвертый параметр ‑ значение типа НазначениеТипаXML, определяющее необходимость явного указания типа данных XML.

И, наконец, у последнего варианта вызова после параметра, указывающего имя корневого элемента XML, появляется еще один параметр ‑ строковое значение, обозначающее пространство имен, к которому относится корневой элемент. Последний параметр по-прежнему имеет тип НазначениеТипаXML.

Копировать в буфер обмена
...
Знач = "Строка такая";
ЗаписатьXML(Зп, Знач);
ЗаписатьXML(Зп, Знач, "Root", НазначениеТипаXML.Явное);
ЗаписатьXML(Зп, Знач, "Root", "urn:some namespace");
...

В результате выполнения приведенного выше фрагмента будет получен следующий XML-фрагмент.

Копировать в буфер обмена
...
<string>Строка такая</string>
<Root xsi:type="xsd:string">Строка такая</Root>
<d1p1:Root xmlns:d1p1="urn:some namespace">Строка такая</d1p1:Root>
...
15.2.3.2.4. Чтение из XML-файла

Метод ПрочитатьXML() предназначен для чтения значений из XML. Данный метод имеет один обязательный параметр ‑ объект ЧтениеXML, из которого должно быть прочитано значение. В качестве второго параметра может быть указан тип значения, которое должно быть прочитано из XML. Если тип значения явно указан в XML, то в качестве второго параметра может быть указано значение Неопределено, или же он может быть вообще опущен. В этом случае метод ПрочитатьXML() пытается определить тип читаемого значения по содержимому атрибута xsi:type, а если атрибут xsi:type отсутствует, то по имени элемента. Если не удалось установить тип или значение указанного типа не может быть прочитано из XML, то вызывается исключение. При удачном завершении метод ПрочитатьXML() возвращает считанное значение.

Следует обратить внимание на то, как считываются менеджеры значений констант, объекты базы данных и наборы записей. После успешного выполнения чтения метод ПрочитатьXML() возвращает считанное из XML значение, но это значение еще не записано в базу данных. Если, например, считан элемент справочника, то для того, чтобы считанный элемент справочника оказался записанным в базу данных, необходимо обратиться к его методу Записать(), как и при «обычной» записи измененного состояния объекта. Это же относится и к другим объектам базы данных, менеджерам записи констант и наборам записей.

При чтении объекта базы данных из XML в базе данных производится поиск объекта с таким же значением ссылки. Если такой объект найден, то считывание из XML выглядит так, как будто объект был прочитан из базы данных, после чего значения его реквизитов, табличных частей и т. п. перезаписываются полученными из XML значениями. Если же объект по ссылке не найден, то считывание из XML выглядит как создание нового объекта, установка ему значения ссылки и заполнение его содержимого значениями, прочитанными из XML.

Метод ПрочитатьXML() позволяет считывать также объекты, которые содержат только часть данных объекта (неполное чтение). Такое чтение выполняется в том случае, если элемент, описывающий объект, содержит необязательный атрибут dataPart. Если этот атрибут установлен в значение false (значение по умолчанию), то чтение объекта будет выполняться так, как описано ранее в этом разделе. Если атрибут dataPart имеет значение true, то чтение объекта будет выполняться следующим образом:

● По читаемому элементу определяется тип объекта (по имени или атрибуту xsi:type).

● Из элемента считываются все ключевые атрибуты объекта (ссылка для ссылочного объекта или основной отбор для регистра). Если ключевые поля не заполнены ‑ формируется исключение.

● Объект считывается из базы данных (включая все дочерние объекты) или создается новый. Для нового ссылочного объекта устанавливается ссылка нового, которая прочитана из xml-файла.

● Из xml-файла выполняется считывание реквизитов и заполнение соответствующих реквизитов объекта. Сопоставление выполняется по имени реквизита (в качестве имени выступает имя xml-элемента). Если в объекте нет реквизита с именем, прочитанным из xml-файла, то будет сформировано исключение.

Неполное чтение поддерживается для следующих объектов метаданных: справочник, документ, задача, бизнес-процесс, планы обмена, счетов, видов расчета и видов характеристик, регистры сведений, накоплений, бухгалтерии и расчета.

Метод ВозможностьЧтенияXML() определяет, возможно ли считывание значения из объекта ЧтениеXML, находящегося в текущей позиции документа XML. Объект ЧтениеXML передается данному методу в качестве параметра. Если метод возвращает Истина, то чтение возможно; если Ложь ‑ значение не может быть считано.

Метод ПолучитьXMLТип() позволяет получить из объекта ЧтениеXML тип данных XML, соответствующий текущей позиции документа XML. Данный метод также имеет один параметр ‑ ЧтениеXML.

15.2.4. Планы обмена

Планы обмена являются центром, вокруг которого группируются прочие механизмы, связанные с обменом данными. В одной конфигурации может быть определено произвольное количество планов обмена. Каждый из планов обмена определяет набор данных, которыми предполагается обмениваться в рамках данного плана обмена. Вместе с набором данных могут определяться и специфические форматы представления этих данных.

Предполагается, что форматы данных основаны на XML, но благодаря гибкости языка XML и наличию развитых средств работы с XML в системе «1С:Предприятие» остается достаточно большое пространство для творчества в области способов представления данных.

В планах обмена можно выделить две значимые составляющие:

● инфраструктура сообщений,

● служба регистрации изменений.

Элементами данных плана обмена являются узлы плана обмена, подобно тому, как элементами данных справочника являются элементы справочника. Каждый из узлов плана обмена обозначает участника обмена данными по данному плану обмена. Один из узлов соответствует данной информационной базе, а остальные ‑ другим участникам, с которыми данная информационная база может обмениваться данными.

Данные переносятся между узлами с помощью сообщений. Средства работы с сообщениями образуют инфраструктуру сообщений. Каждое сообщение относится к определенному плану обмена, имеет определенный узел-отправитель и определенный узел-получатель. Сообщение не может быть отправлено неизвестному узлу и не может быть принято от неизвестного узла. Каждое сообщение имеет свой собственный целочисленный номер.

Служба регистрации изменений предназначена для регистрации изменений данных, производимых системой «1С:Предприятие», чтобы при обмене данными иметь возможность передавать не все данные, а только измененные.

Таким образом, планы обмена определяют набор механизмов, предназначенных для организации обмена данными. Рассмотрим эти механизмы подробнее.

15.2.4.1. Узлы планов обмена

При создании нового плана обмена в нем автоматически создается один узел ‑ этот узел или узел плана обмена, соответствующий данной информационной базе. Остальные узлы, то есть узлы, с которыми данный узел может обмениваться данными, в рамках плана обмена автоматически не создаются.

Для каждого узла должен быть определен уникальный код, так как при обмене данными узел идентифицируется по коду. Коды узлов задаются таким образом, чтобы обменивающиеся стороны «узнали» друг друга.

Примечание. План обмена не может быть без кода и наименования. Другими словами, для стандартных реквизитов плана обмена Код и Наименование нельзя установить длину, равной 0.

Предположим, требуется организовать обмен данными между двумя информационными базами по плану обмена с именем УдаленныеСклады. Одна из этих информационных баз выполняет функции центрального офиса, а другая ‑ удаленного склада.

В этом случае было бы целесообразно в качестве значения кода этого узла плана обмена УдаленныеСклады в первой информационной базе задать значение Офис (если, конечно, позволяет длина кода), а во второй ‑ Склад1. Таким образом, эти узлы будут поименованы. Но этого недостаточно, ведь нужно еще задать узлы, с которыми будет производиться обмен данными. Для этого в первой информационной базе в плане обмена УдаленныеСклады следует создать узел с кодом Склад1, а во второй информационной базе ‑ узел с кодом Офис.

Таким образом, первая информационная база будет «знать», что в рамках плана обмена УдаленныеСклады ее саму «зовут» Офис и она будет вести обмен с узлом по имени Склад1; а вторая ‑ что ее «зовут» Склад1, а обмениваться данными она будет с узлом Офис.

15.2.4.2. Инфраструктура сообщений

Важнейшей составляющей инфраструктуры сообщений являются сами сообщения. Как уже отмечалось, сообщения передаются в рамках плана обмена от одного узла другому. То есть каждое сообщение точно ассоциировано с планом обмена, имеет одного отправителя и одного получателя.

Рассмотрим, что такое сообщение. Сообщение оформляется как документ XML, имеющий определенную структуру. В качестве примера приведем следующее сообщение:

Копировать в буфер обмена
<v8msg:Message xmlns:v8msg="http://v8.1c.ru/messages">
    <v8msg:Header>
   <v8msg:ExchangePlan>УдаленныеСклады</v8msg:ExchangePlan>
   <v8msg:To>Склад1</v8msg:To>
   <v8msg:From>Офис</v8msg:From>
   <v8msg:MessageNo>20</v8msg:MessageNo>
   <v8msg:ReceivedNo>15</v8msg:ReceivedNo>
    </v8msg:Header>
    <v8msg:Body>
   <!--Тело сообщения -->
    </v8msg:Body>
</v8msg:Message>

Все сообщение находится внутри элемента XML с именем Message, относящимся к пространству имен http://v8.1c.ru/messages. Сообщение делится на заголовок и тело сообщения. Соответственно, элемент Message содержит два вложенных элемента с именами Header и Body. Оба относятся к пространству имен http://v8.1c.ru/messages.

Элемент Header содержит заголовок сообщения. Структура заголовка жестко задана. Информация заголовка представлена в нескольких элементах XML, вложенных в элемент Header. Все элементы, вложенные в элемент Header, относятся к пространству имен http://v8.1c.ru/messages:

ExchangePlan содержит имя плана обмена, к которому относится сообщение.

To содержит код узла, для которого предназначено сообщение.

From содержит код узла-отправителя.

MessageNo содержит номер данного сообщения. Номер сообщения является положительным целым числом и присваивается узлом-отправителем. Номер каждого последующего сообщения равен номеру предыдущего отправленного сообщения плюс 1.

ReceivedNo содержит максимальный номер сообщения, которое узел-отправитель данного сообщения принял от узла-получателя данного сообщения. Данное значение включено в состав заголовка сообщения для подтверждения приема сообщений.

Тело сообщения содержится в элементе XML с именем Body, относящимся к пространству имен http://v8.1c.ru/messages. Данный элемент может иметь произвольное содержимое, определяемое прикладными потребностями. Инфраструктурой сообщений содержимое тела сообщения никак не регламентируется.

15.2.4.3. Служба регистрации изменений

Суть регистрации изменений состоит в том, чтобы иметь перечень измененных элементов данных. Эти элементы данных должны быть переданы в очередном сообщении тому или иному узлу, с которым производится обмен данными. При каждом изменении данных должно быть зарегистрировано, что имеются изменения и их предстоит передать во все узлы, с которыми поддерживается обмен этими данными. При получении подтверждения приема сообщения, в котором были отправлены изменения, записи регистрации изменений должны быть удалены.

Регистрация изменений может выполняться для следующих элементов данных:

КонстантаМенеджерЗначения.<Имя константы>;

● Объекты базы данных:

СправочникОбъект.<Имя справочника>;

ДокументОбъект.<Имя документа>;

ПланСчетовОбъект.<Имя плана счетов>;

ПланВидовХарактеристикОбъект.<Имя плана видов характеристик>;

ПланВидовРасчетаОбъект.<Имя плана видов расчета>;

БизнесПроцессОбъект.<Имя бизнес-процесса>;

ЗадачаОбъект.<Имя задачи>.

● Наборы записей:

РегистрСведенийНаборЗаписей.<Имя регистра сведений>;

РегистрБухгалтерииНаборЗаписей.<Имя регистра бухгалтерии>;

РегистрНакопленияНаборЗаписей.<Имя регистра накопления>;

ПоследовательностьНаборЗаписей.<Имя последовательности>;

РегистрРасчетаНаборЗаписей.<Имя регистра расчета>.

ПерерасчетНаборЗаписей.<Имя перерасчета>.

Для каждого из приведенных элементов данных ведется своя таблица регистрации изменений. Таблицы имеют разную структуру, в зависимости от того, для каких элементов данных регистрируются изменения, но все-таки структуры таблиц подобны. В структуре можно выделить три составляющих:

● ключ элемента данных, для которого регистрируются изменения;

● ссылка на узел, в который изменение должно быть передано;

● номер сообщения, в котором изменение передано в первый раз.

Структуры таблиц регистрации изменений для разных данных отличаются ключом, так как ключи у разных данных разные:

● для константы ключом является идентификатор константы;

● для объектов базы данных в качестве ключа используется ссылка на объект;

● для наборов записей, для которых определен регистратор, в качестве ключа используется ссылка на объект-регистратор;

● для набора записей регистра сведений, если регистратор не определен, в качестве ключа используется совокупность измерений, входящих в основной отбор; а если регистр сведений является периодическим и включен основной отбор по периоду, то в ключ входит еще и период.

Изменение элемента данных должно быть зарегистрировано для всех узлов, в которые изменение должно быть передано. Таким образом, в результате изменения элемента данных в таблице регистрации изменений должно появиться N записей, где N ‑ количество узлов, для которых регистрируются изменения. В каждой из этих записей указано одно и то же значение ключа элемента данных и различные значения ссылки на узел.

Непосредственно после выполнения регистрации изменения номер сообщения имеет значение NULL. При первой отправке изменения в данное поле помещается номер сообщения, в котором изменение отправлено.

При конфигурировании плана обмена определяется так называемый состав плана обмена. В состав плана обмена включаются объекты метаданных. Вхождение объекта метаданных в состав плана обмена показывает, что изменения данных, соответствующих объекту метаданных, могут регистрироваться для узлов данного плана обмена. Если объект метаданных не входит в состав ни одного плана обмена, то для данного объекта не создается таблица регистрации изменений и регистрация изменений данных не выполняется.

При определении вхождения объекта метаданных в состав плана обмена указывается свойство Авторегистрация. Авторегистрацию можно разрешить или запретить. Если авторегистрация разрешена, то при изменении данных регистрация будет выполнена автоматически. Если запрещена, то регистрацию изменения можно выполнить вручную.

15.2.4.4. Доступ к механизмам планов обмена средствами встроенного языка

Для работы с планами обмена из встроенного языка предусмотрен ряд объектов.

Объект ПланыОбменаМенеджер помимо традиционной для такого рода менеджеров функциональности содержит методы для работы со службой регистрации изменений ЗарегистрироватьИзменения(), УдалитьРегистрациюИзменений(), ИзменениеЗарегистрировано(), ВыбратьИзменения(), а также методы для создания объектов, читающих и записывающих сообщения: СоздатьЧтениеСообщения(), СоздатьЗаписьСообщения().

Для объекта ПланОбменаМенеджер.<Имя плана обмена> наиболее важной особенностью является наличие метода ЭтотУзел(), возвращающего ссылку на узел данного плана обмена, соответствующий данной информационной базе (далее используется термин «этот узел»). Для определения узла плана обмена, соответствующего данной информационной базы, также служит стандартный реквизит ЭтотУзел. Значение этого реквизита (ЭтотУзел) можно изменять. Основной вариант применения этой операции ‑ восстановление корректного состояния информационной базы после того, как произошло восстановление данных из файла XML. В этом случае необходимо назначить в восстановленной базе в качестве «этого узла» тот элемент плана обмена, который был установлен в базе-источнике. Это особенно актуально в том случае, когда ссылки на «этот узел» плана обмена были запомнены в каких-либо объектах информационной базы. Рассмотрим процесс замены «этого узла» более подробно.

Обычной записью элемента плана обмена с установленным (или сброшенным) свойством ЭтотУзел выполнить данную операцию невозможно (при наличии в системе элемента плана обмена с установленным свойством ЭтотУзел) ‑ система выдаст исключение. Для того чтобы выполнить эту операцию, необходимо выполнить следующие действия:

1. Для элемента, который планируется установить новым элементом «этот узел», следует установить свойство ЭтотУзел в режиме ОбменДанными.Загрузка = Истина (см. здесь).

2. Для элемента, который ранее был элементом «этот узел», следует сбросить свойство ЭтотУзел (обычным образом).

3. Рекомендуется эти действия (установку нового и отключение старого узла) выполнять в транзакции.

Пример смены элемента «этот узел»:

Копировать в буфер обмена
НачатьТранзакцию();
ТекущийЭтотУзел = ПланыОбмена.ОбменДанными.ЭтотУзел();
НовыйОбъект = НовыйЭтотУзел.ПолучитьОбъект();
НовыйОбъект.ОбменДанными.Загрузка = Истина;
НовыйОбъект.ЭтотУзел = Истина;
НовыйОбъект.Записать();
ТекущийОбъект = ТекущийЭтотУзел.ПолучитьОбъект();
ТекущийОбъект.ЭтотУзел = Ложь;
ТекущийОбъект.Записать();
ЗафиксироватьТранзакцию();

При смене ЭтотУзел следует иметь ввиду несколько особенностей поведения системы:

1. Если завершить работу системы в ситуации, когда у плана обмена отсутствует элемент «этот узел», то при старте система автоматически создаст новый элемент плана обмена с установленным свойством ЭтотУзел.

2. Если в системе создана два элемента со значением свойства ЭтотУзел равным значением Истина, то поведение системы в этом случае становится неопределенным.

ПланОбменаОбъект.<Имя плана обмена> соответствует узлу плана обмена. Особого внимания заслуживают свойства НомерОтправленного и НомерПринятого. Свойство НомерОтправленного содержит номер последнего сообщения, отправленного из данной информационной базы в адрес узла, которому соответствует объект ПланОбменаОбъект.<Имя плана обмена>. Свойство НомерПринятого содержит максимальный из номеров сообщений, принятых данной информационной базой от узла, которому соответствует объект ПланОбменаОбъект.<Имя плана обмена>.

15.2.4.4.1. Регистрация изменений
Автоматическая регистрация

Как уже отмечалось, регистрация изменений может выполняться автоматически при записи или удалении элемента данных. Рассмотрим, как это происходит. У каждого из объектов, чьи изменения могут быть зарегистрированы планом обмена, имеется свойство ОбменДанными с типом ПараметрыОбменаДанными. Данное свойство может быть использовано только для чтения и предназначено для управления различными параметрами при обмене данными.

У объекта ПараметрыОбменаДанными есть свойство Получатели, имеющее тип НаборУзлов. В данном свойстве хранится перечень узлов, для которых будет выполняться регистрация изменений при записи или удалении данных. Список получателей заполняется автоматически перед тем, как будет вызван обработчик ПередЗаписью() при выполнении записи данных или ПередУдалением() при выполнении удаления. Однако автоматическое заполнение будет выполнено только в том случае, если свойство Автозаполнение объекта НаборУзлов имеет значение Истина (Истина является значением по умолчанию для свойства Автозаполнение). При автоматическом заполнении в список получателей попадают ссылки на все узлы всех планов обмена, в состав которых входит соответствующий объект метаданных, при условии, что значением свойства Авторегистрация является Разрешить. Само собой разумеется, что узлы, соответствующие данной информационной базе, при этом в список получателей не попадут. При выполнении автоматического заполнения список получателей предварительно очищается.

В обработчике ПередЗаписью() (и/или ПередУдалением()) в список получателей можно внести изменения: добавить или удалить ссылки на узлы. Однако следует помнить, что список получателей может содержать только ссылки на узлы, относящиеся к планам обмена, в состав которых входит соответствующий объект метаданных.

В приведенном ниже примере обработчик ПередЗаписью() исключает из списка получателей узел с кодом Особый плана обмена УдаленныеСклады.

Копировать в буфер обмена
Процедура ПередЗаписью()
    Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Особый");
    ОбменДанными.Получатели.Удалить(Узел);
КонецПроцедуры

Присвоив свойству Автозаполнение значение Ложь, можно добиться того, что автоматическое заполнение списка получателей выполняться не будет. В этом случае действия со списком получателей можно производить не только в обработчике ПередЗаписью(), но и в любом фрагменте кода, как показано в примере.

Копировать в буфер обмена
Объект = Ссылка.ПолучитьОбъект();
Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад1");
Объект.ОбменДанными.Получатели.Автозаполнение = Ложь;
Объект.ОбменДанными.Получатели.Добавить(Узел);
Объект.Записать();
Принудительная регистрация одного или нескольких объектов

У объекта ПланыОбменаМенеджер реализован ряд методов для регистрации изменений. Прежде всего, это метод ЗарегистрироватьИзменения(). Данный метод позволяет выполнять регистрацию изменений одиночных элементов данных или целых групп для одного или нескольких узлов. Первый параметр данного метода ‑ ссылка на узел плана обмена или массив ссылок на узлы, для которых выполняется регистрация изменений. Если первый параметр представляет собой одиночную ссылку на узел, то второй параметр может быть опущен (или установлен в значение Неопределено). При этом выполняется регистрация изменений всех элементов данных, которые на данный момент присутствуют в базе данных и изменения которых могут быть зарегистрированы для данного узла.

Это может быть полезно для организации начальной передачи данных вновь созданному узлу.

Копировать в буфер обмена
Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Новый");
ПланыОбмена.ЗарегистрироватьИзменения(Узел);

Если же первый параметр представляет собой массив ссылок на узлы, то второй параметр должен быть указан обязательно. Впрочем, второй параметр может присутствовать и в том случае, если первый параметр ‑ одиночная ссылка на узел. В зависимости от способа задания второго параметра можно зарегистрировать изменения одного элемента данных, некоторого набора элементов данных или же всех данных, относящихся к одному объекту метаданных.

Для регистрации изменений одного элемента в качестве второго параметра может быть указана ссылка на объект базы данных (или значение основного отбора для регистра) или объект типа УдалениеОбъекта.

Если указана ссылка на объект информационной базы или значение основного отбора, то будет выполнена регистрация объекта.

Копировать в буфер обмена
Узлы = Новый Массив(2);
Узлы[0] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад1");
Узлы[1] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад2");
Данные = Справочники.Номенклатура.НайтиПоКоду("ТП00127");
ПланыОбмена.ЗарегистрироватьИзменения(Узлы, Данные);

Если выбран элемент УдалениеОбъекта, то будет зарегистрирована необходимость удаления некоторого объекта, на который ссылается объект УдалениеОбъекта.

Копировать в буфер обмена
Узлы = Новый Массив(2);
Узлы[0] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад1");
Узлы[1] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад2");
Данные = Справочники.Номенклатура.НайтиПоКоду("ТП00127");
ПланыОбмена.ЗарегистрироватьИзменения(Узлы, Новый УдалениеОбъекта(Данные));

Для того, чтобы зарегистрировать изменения нескольких объектов, для регистрации изменений надо использовать или объект метаданных, или массив элементов данных.

Если в качестве второго параметра метода ЗарегистрироватьИзменения() передать объект метаданных, то будут зарегистрированы все объекты данных, относящиеся к указанному объекту метаданных.

Копировать в буфер обмена
Узлы = Новый Массив(2);
Узлы[0] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад1");
Узлы[1] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад2");
ПланыОбмена.ЗарегистрироватьИзменения(Узлы, Метаданные.Справочники.Номенклатура);

Имеется возможность зарегистрировать изменения по некоторому списку объектов. Для этого необходимо в качестве второго параметра метода регистрации изменений передать массив, который может состоять из ссылок на объекты данных и объектов УдалениеОбъекта. Элементы массива не обязательно должны относиться к одному объекту метаданных. В качестве элементов массива не могут выступать объекты метаданных и значение Неопределено. При таком вызове изменения будут зарегистрированы для всех объектов, которые расположены в массиве. При этом все изменения будут выполнены в рамках одной транзакции.

Копировать в буфер обмена
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Документ.РасходнаяНакладная ГДЕ Склад = &Склад");
Запрос.УстановитьПараметр("Склад", Узел.Склад);
СписокСсылок = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
ПланыОбмена.ЗарегистрироватьИзменения(Узел, СписокСсылок);
Удаление регистрации одного или нескольких объектов

Для удаления записей регистрации изменений у объекта ПланыОбменаМенеджер имеется метод УдалитьРегистрациюИзменений(). С его помощью можно выполнить удаление записей регистрации изменений для всех данных, которые зарегистрированы для узла.

Копировать в буфер обмена
Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад1");
ПланыОбмена.УдалитьРегистрациюИзменений(Узел);

Можно удалить записи регистрации изменений конкретного элемента данных для одного или нескольких узлов.

Копировать в буфер обмена
Узлы = Новый Массив(2);
Узлы[0] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад1");
Узлы[1] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад2");
Данные = Справочники.Номенклатура.НайтиПоКоду("ТП00127");
ПланыОбмена.УдалитьРегистрациюИзменений(Узлы, Данные);

Также можно удалить записи регистрации изменений всех данных, относящихся к объекту метаданных для одного или нескольких узлов.

Копировать в буфер обмена
Узлы = Новый Массив(2);
Узлы[0] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад1");
Узлы[1] = ПланыОбмена.УдаленныеСклады.НайтиПоКоду("Склад2");
ПланыОбмена.УдалитьРегистрациюИзменений(Узлы, Метаданные.Справочники.Номенклатура);

Кроме того, если в качестве первого параметра указан одиночный узел, то в качестве второго параметра может быть указан номер сообщения. В этом случае метод УдалитьРегистрациюИзменений() удаляет из всех таблиц регистрации изменений все записи, относящиеся к указанному узлу, у которых номер сообщения меньше или равен значению второго параметра (но не NULL). Данная форма метода предназначена для удаления записей регистрации изменений, по которым получено подтверждение приема изменений от узла, указанного в первом параметре.

Отменить регистрацию можно по некоторому списку объектов (аналогично регистрации изменений). Для выполнения этой операции необходимо в качестве второго параметра метода отмены регистрации указать массив со ссылками на объекты, для которых необходимо отменить регистрацию изменений. В состав массива не могут входить значения типа Число, объекты метаданных и значение Неопределено. В случае использования списка объектов, удалены будут зарегистрированные изменения только для переданных (в качестве параметра) объектов.

Проверка регистрации изменений

Для проверки, зарегистрировано ли изменение элемента данных для того или иного узла, служит метод ИзменениеЗарегистрировано(). Первый параметр данного метода ‑ ссылка на узел, а второй параметр ‑ элемент Данные, ссылка на объект базы данных или УдалениеОбъекта.

15.2.4.4.2. Запись сообщений обмена данными

Для записи сообщений предназначен объект ЗаписьСообщенияОбмена.

Объект ЗаписьСообщенияОбмена создается при обращении к методу СоздатьЗаписьСообщения() объекта ПланыОбменаМенеджер.

Объект ЗаписьСообщенияОбмена имеет три метода:

НачатьЗапись(),

ЗакончитьЗапись(),

ПрерватьЗапись().

У метода НачатьЗапись() два параметра: объект типа ЗаписьXML, через который будет записываться сообщение, и ссылка на узел, которому адресовано сообщение. Метод НачатьЗапись() вычисляет номер сообщения путем прибавления 1 к номеру предыдущего сообщения; производит запись начала элемента XML, содержащего все сообщение, заголовка сообщения целиком, а также начала элемента XML, содержащего тело сообщения. После этого можно приступать к записи содержимого тела сообщения.

Для нормального завершения записи сообщения предназначен метод ЗакончитьЗапись(). При обращении к этому методу производится запись конца элемента XML, содержащего тело сообщения, и конца элемента XML, содержащего все сообщение. После успешной записи элементов XML, завершающих сообщение, сообщение считается отправленным, и его номер запоминается как номер последнего отправленного сообщения от данного узла узлу-получателю.

Если есть необходимость прервать запись сообщения и не считать его отправленным, то следует обратиться к методу ПрерватьЗапись().

Ниже приведен типовой фрагмент кода, выполняющий запись сообщения обмена данными.

Копировать в буфер обмена
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.ОткрытьФайл(ИмяФайлаСообщения);
Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду(КодУзла);
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Узел);
// Запись тела сообщения
ЗаписьСообщения.ЗакончитьЗапись();

Тело сообщения может содержать любые данные, представленные в XML, в зависимости от того, какой формат принят для того или иного плана обмена. Здесь же будет рассмотрен случай, когда сообщение содержит данные, изменения которых зарегистрированы службой регистрации изменений. Для реализации этого следует выбрать зарегистрированные изменения, обойти их и поместить XML-представления измененных данных в сообщение.

Для выборки изменений предназначен метод ВыбратьИзменения() объекта ПланыОбменаМенеджер. Данный метод имеет два параметра: ссылка на узел, для которого выбираются изменения, и номер сообщения, в которое изменения должны быть помещены. Метод ВыбратьИзменения() возвращает объект типа ВыборкаДанных, содержащий ключи данных, изменения которых были зарегистрированы для узла, переданного в качестве первого параметра. Кроме того, метод ВыбратьИзменения() помещает номер сообщения, переданный в качестве второго параметра, в соответствующие поля отобранных записей таблиц регистрации изменений, если в этих полях содержалось значение NULL.

Выборка данных, которая получается в результате использования метода ВыбратьИзменения(), включает объекты в следующем порядке:

● Константы.

● Планы видов характеристик.

● Планы счетов.

● Планы видов расчета.

● Справочники.

● Прочие ссылочные объекты информационной базы (кроме тех объектов, которые перечислены ранее). Порядок следования прочих ссылочных объектов в выборке не определен.

● Наборы записей регистров (кроме наборов записей регистров расчета). Порядок следования наборов записей в выборке не определен.

● Наборы записей регистров расчета.

● Данные последовательностей.

В рамках каждой группы изменений порядок не определен. Другими словами, нельзя явно указать, каким будет порядок следования элементов справочников, чьи изменения зарегистрированы в плане обмена, из которого идет выборка.

Если изменение уже было выбрано при предыдущем обращении, то номер сообщения в соответствующей записи таблицы регистрации изменений не модифицируется; а если изменение еще не выбиралось, то при выборке запоминается номер первого сообщения, для которого изменения были выбраны.

Для обхода выбранных изменений объект ВыборкаДанных имеет методы Следующий() и Получить(). При обращении к методу Следующий() происходит переход к следующему ключу в выборке. При первом обращении к методу Следующий() происходит переход к первому ключу. При обращении к методу Получить() происходит выборка из базы данных элемента данных, соответствующего текущему ключу выборки. Здесь следует сделать отдельное замечание относительно удаленных объектов базы данных. Если регистрация изменения объекта базы данных была выполнена в результате его удаления, то метод Получить() вернет не объект базы данных, а объект типа УдалениеОбъекта.

Помещение XML-представления элементов данных в сообщение выполняется при помощи метода ЗаписатьXML() глобального контекста.

Ниже приведен фрагмент кода, в котором выполняется формирование сообщения и в тело которого помещаются зарегистрированные изменения данных.

Копировать в буфер обмена
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.ОткрытьФайл(ИмяФайлаСообщения);
Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду(КодУзла);
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Узел);
Выборка = ПланыОбмена.ВыбратьИзменения(Узел, ЗаписьСообщения.НомерСообщения);
Пока Выборка.Следующий() Цикл
    Данные = Выборка.Получить();
    ЗаписатьXML(ЗаписьXML, Данные);
КонецЦикла;
ЗаписьСообщения.ЗакончитьЗапись();
15.2.4.4.3. Чтение сообщений обмена данными

Для чтения сообщений обмена данными предназначен объект ЧтениеСообщенияОбмена.

Объект создается при обращении к методу СоздатьЧтениеСообщения() объекта ПланыОбменаМенеджер.

Объект ЧтениеСообщенияОбмена имеет три метода:

НачатьЧтение(),

ЗакончитьЧтение(),

ПрерватьЧтение().

У метода НачатьЧтение() два параметра: объект типа ЧтениеXML, через который производится чтение сообщения, и значение перечисления ДопустимыйНомерСообщения.

Метод НачатьЧтение() считывает начало элемента XML, содержащего все сообщение, читает заголовок сообщения и проверяет его приемлемость:

● определен ли план обмена, к которому относится сообщение;

● правильно ли заданы отправитель и получатель сообщения;

● допустимый ли номер имеет сообщение.

Допустимость номера сообщения определяется с учетом значения второго параметра. Если второй параметр имеет значение ДопустимыйНомерСообщения.Любой, то читаемое сообщение может иметь любой номер. Если значение второго параметра ДопустимыйНомерСообщения.Следующий, то номер сообщения должен быть в точности на 1 больше максимального из номеров ранее принятых сообщений. А если второй параметр принимает значение ДопустимыйНомерСообщения.Больший, то номер сообщения просто должен быть больше максимального из номеров ранее принятых сообщений. Значением по умолчанию для второго параметра является ДопустимыйНомерСообщения.Больший.

После этого считывается начало элемента XML, содержащего тело сообщения. Если сообщение не является допустимым или при чтении произошла ошибка, то вызывается исключение. Если же все нормально, то можно приступать к чтению тела сообщения.

Для нормального завершения чтения сообщения используется метод ЗакончитьЧтение(). Данный метод считывает конец элемента XML, содержащего тело элемента, и конец элемента XML, содержащего все сообщения. Если все хорошо, то сообщение считается принятым, и номер сообщения, если он больше максимального из номеров ранее принятых сообщений, запоминается как максимальный номер принятого сообщения.

Метод ПрерватьЧтение() позволяет прервать чтение сообщения в любой момент.

Ниже приведен типовой фрагмент кода, в котором показано использование объекта ЧтениеСообщенияОбмена.

Копировать в буфер обмена
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения);
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML, ДопустимыйНомерСообщения.Больший);
// Чтение тела сообщения
ЧтениеСообщения.ЗакончитьЧтение();

Как уже отмечалось, тело сообщения может в принципе содержать любую информацию, но здесь будет рассмотрен случай считывания из тела сообщения измененных данных. Фрагмент кода, в котором производится чтение сообщения, содержащего измененные данные, выглядит следующим образом.

Копировать в буфер обмена
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения);
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
ПланыОбмена.УдалитьРегистрациюИзменений(ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерСообщения);
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
    Данные = ПрочитатьXML(ЧтениеXML);
    Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель;
    Данные.ОбменДанными.Загрузка = Истина;
    Данные.Записать();
КонецЦикла;
ЧтениеСообщения.ЗакончитьЧтение();

Обращение к методу УдалитьРегистрациюИзменений() объекта МенеджерПлановОбмена предназначено для удаления записей регистрации, по которым произведено подтверждение приема. Далее из тела сообщения с помощью метода ПрочитатьXML() считываются данные, пока имеется возможность считывания. Перед записью данных в базу данных производится изменение двух свойств объекта ПараметрыОбменаДанными, который принадлежит объекту, представляющему считанные из XML данные. В свойстве Отправитель указывается узел-отправитель данных, чтобы не производить регистрацию изменений для отправки в узел, откуда эти данные только что были получены. Установка свойству Загрузка значения Истина означает, что запись производится в рамках загрузки данных, а не обычной записи. В этом случае при записи не будут производиться некоторые проверки.

15.2.4.4.4. Гарантированная доставка сообщений

В рассмотренных примерах чтения и записи сообщений обмена данными предполагалось, что отправленные сообщения могут быть потеряны по тем или иным причинам. Поэтому при записи сообщений в них помещались все зарегистрированные изменения, в том числе и те, которые уже были отправлены, но по ним еще не получено подтверждение приема.

При приеме допустимым считается сообщение с номером большим, чем максимальный из номеров принятых сообщений. Удаление регистрации изменений производится только для номеров сообщений, прием которых подтвержден.

Копировать в буфер обмена
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
ПланыОбмена.УдалитьРегистрациюИзменений(ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);

Такая логика считается типовой при реализации обмена данными. Однако можно реализовать и вариант, при котором доставка сообщений считается гарантированной. В этом случае удаление регистрации изменений должно производиться непосредственно после удачного завершения записи сообщения, чтобы отправка уже отправленных изменений не повторялась. А приниматься может только то сообщение, номер которого на 1 больше максимального из номеров ранее принятых сообщений.

В этом случае ранее приведенный фрагмент кода, в котором выполняется запись сообщения, будет выглядеть следующим образом.

Копировать в буфер обмена
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.ОткрытьФайл(ИмяФайлаСообщения);
Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду(КодУзла);
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Узел);
Выборка = ПланыОбмена.ВыбратьИзменения(Узел, ЗаписьСообщения.НомерСообщения);
Пока Выборка.Следующий() Цикл
    Данные = Выборка.Получить();
    ЗаписатьXML(ЗаписьXML, Данные);
КонецЦикла;
НомерСообщения = ЗаписьСообщения.НомерСообщения;
ЗаписьСообщения.ЗакончитьЗапись();
ПланыОбмена.УдалитьРегистрациюИзменений(Узел, НомерСообщения);

Фрагмент кода, в котором происходит прием сообщения, будет выглядеть следующим образом:

Копировать в буфер обмена
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения);
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML, ДопустимыйНомерСообщения.Следующий);
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
    Данные = ПрочитатьXML(ЧтениеXML);
    Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель;
    Данные.ОбменДанными.Загрузка = Истина;
    Данные.Записать();
КонецЦикла;
ЧтениеСообщения.ЗакончитьЧтение();

Следует учитывать, что организация гарантированной доставки может быть достаточно сложной, и в большинстве случаев предпочтительно повторно посылать изменения до получения подтверждения их приема.

15.2.4.4.5. Разрешение коллизий

В приведенных выше примерах чтения и записи сообщений не учитывалось, что при обмене данными один и тот же элемент данных может быть изменен одновременно в двух обменивающихся данными узлах. В этом случае непонятно, какое из изменений должно быть в конечном счете принято. Такая ситуация называется коллизией.

Одним из способов разрешения коллизий может быть определение, какой из узлов является главным, а какой ‑ подчиненным. При этом должно быть принято изменение, сделанное в главном узле; а изменение, сделанное в подчиненном узле, должно быть отвергнуто.

Для реализации этого при приеме сообщения перед записью данных необходимо установить, зарегистрировано ли изменение этих данных, и, в зависимости от роли узла в данной паре получатель-отправитель, принять решение: записывать или не записывать данные.

Ниже приведен пример реализации стратегии «главный ‑ подчиненный» при чтении сообщения. Предполагается, что для хранения роли узла в плане обмена был определен реквизит Главный, имеющий тип Булево.

Копировать в буфер обмена
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения);
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
ПланыОбмена.УдалитьРегистрациюИзменений(ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерСообщения);
Отправитель = ЧтениеСообщения.Отправитель;
Главный = Отправитель.Главный;
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
    Данные = ПрочитатьXML(ЧтениеXML);
    Если Главный Или Не ПланыОбмена.ИзменениеЗарегистрировано(Отправитель, Данные) Тогда
   Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель;
   Данные.ОбменДанными.Загрузка = Истина;
   Данные.Записать();
    КонецЕсли;
КонецЦикла;
ЧтениеСообщения.ЗакончитьЧтение();
15.2.4.4.6. Задание соответствий пространств имен

При записи сообщения, после выполнения метода НачатьЗапись() объекта ЗаписьСообщенияОбмена, не определено никаких соответствий пространств имен. В то же время ряд пространств имен может многократно использоваться при записи отдельных элементов данных. В этом случае определения соответствий одних и тех же пространств имен будут многократно встречаться в теле сообщения. Поэтому целесообразно после начала записи сообщения, но до начала записи тела сообщения поместить несколько строк кода, в которых будут определяться соответствия для наиболее часто используемых пространств имен.

Например, как это сделано в приведенном ниже фрагменте записи сообщения.

Копировать в буфер обмена
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.ОткрытьФайл(ИмяФайлаСообщения);
Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду(КодУзла);
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Узел);
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("xsd", "http://www.w3.org/2001/XMLSchema");
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("xsi", "http://www.w3.org/2001/XMLSchema instance");
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("v8", "http://v8.1c.ru/data");
Выборка = ПланыОбмена.ВыбратьИзменения(Узел, ЗаписьСообщения.НомерСообщения);
Пока Выборка.Следующий() Цикл
    Данные = Выборка.Получить();
    ЗаписатьXML(ЗаписьXML, Данные);
КонецЦикла;
НомерСообщения = ЗаписьСообщения.НомерСообщения;
ЗаписьСообщения.ЗакончитьЗапись();
ПланыОбмена.УдалитьРегистрациюИзменений(Узел, НомерСообщения);

В ряде случаев такой прием поможет ощутимо уменьшить размер документа XML, в котором находится сообщение обмена данными.

15.3. Распределенные информационные базы

15.3.1. Общие принципы

Распределенная информационная база ‑ это совокупность информационных баз системы «1С:Предприятие» (узлов распределенной информационной базы), в которых поддерживается синхронизация конфигурации и данных. Распределенная информационная база имеет иерархическую структуру. У каждого узла распределенной информационной базы может быть один главный и произвольное число подчиненных узлов. Самый главный узел, или узел, у которого нет главного узла, называется корневым узлом распределенной информационной базы (база Главная база данных на рис. 502). Каждый из узлов может обмениваться данными только со своими «соседями», то есть со своими главными и подчиненными узлами.

Рис. 502. Иерархическая распределенная информационная база

Изменения конфигурации допускаются только в корневом узле распределенной информационной базы с последующим ее распространением по иерархии от корневого узла к его подчиненным и т. д. Таким образом, механизм управления распределенными информационными базами обеспечивает наличие во всех узлах распределенной информационной базы одной и той же конфигурации.

Изменение данных допускается в любом узле распределенной информационной базы. Синхронизация данных достигается путем распространения изменений данных, произведенных в одном узле, во все структуры распределенной информационной базы.

При организации работы последовательности документов в распределенной информационной базе нужно учитывать, что участие документа в последовательности имеет смысл только в одном узле распределенной информационной базы. Это может быть либо узел, в котором документ был создан, либо другой узел, но узел должен быть один. Нарушение данного принципа может привести к различным проблемам в процессе работы с системой, например, невозможности восстановления последовательности документов.

Если в рамках всей распределенной информационной базы поддерживается полная идентичность конфигурации, то полная идентичность данных необязательна. Состав данных, изменения которых передаются в рамках распределенной информационной базы, может регулироваться как «по вертикали» (путем определения множества объектов метаданных, данные которых участвуют в обмене), так и «по горизонтали» (путем задания условий на передачу и прием изменений на уровне отдельных элементов данных).

15.3.2. Планы обмена

Планы обмена занимают центральное место и в управлении распределенными информационными базами. Но для того, чтобы тот или иной план обмена оказался пригоден для организации распределенной информационной базы, у него при конфигурировании должно быть установлено свойство Распределенная информационная база.

Данные в распределенной информационной базе переносятся с помощью сообщений, предоставляемых инфраструктурой сообщений. В отличие от универсальных механизмов обмена данными, содержимое сообщений, передаваемых между узлами распределенной информационной базы, не может быть произвольным, а является регламентированным протоколом обмена, принятым для распределенной информационной базы.

Номенклатура данных, изменениями которых будет производиться обмен в рамках распределенной информационной базы, определяется составом плана обмена. Вхождение объекта метаданных в состав плана обмена показывает, что изменения данных, соответствующих объекту метаданных, могут регистрироваться для узлов данного плана обмена. Но в отличие от универсальных механизмов обмена данными, номенклатура данных, обмен которыми может производиться в рамках распределенной информационной базы, строго ограничена составом соответствующего плана обмена.

Для регистрации изменений данных в распределенной информационной базе задействована служба регистрации изменений. Элементы данных помещаются в сообщение с использованием механизмов XML-сериализации. Помимо изменений данных, между узлами распределенной информационной базы передаются изменения конфигурации, а также некоторая дополнительная служебная информация. Регистрация изменений конфигурации и их передача в распределенной информационной базе осуществляются полностью автоматически и недоступны для пользователя и разработчика конфигураций.

В отличие от универсальных механизмов обмена данными, формирование и прием сообщения обмена данными в распределенной информационной базе производятся «в одно действие», то есть все содержимое сообщения формируется путем вызова одного метода встроенного языка. Аналогично и считывание содержимого сообщения производится путем вызова одного метода. Для того чтобы управлять составом данных, помещаемых в сообщение, а также считываемых из сообщения и помещаемых в базу данных, на уровне отдельных элементов данных в модуле плана обмена могут быть определены обработчики событий:

ПриОтправкеДанныхПодчиненному,

ПриОтправкеДанныхГлавному,

ПриПолученииДанныхОтПодчиненного,

ПриПолученииДанныхОтГлавного.

Таким образом, в распределенной информационной базе практически полностью задействованы универсальные механизмы обмена данными, но имеются и некоторые дополнительные возможности, недоступные вне распределенной информационной базы.

15.3.2.1. Главный и подчиненный узлы

Как было сказано выше, у каждого из узлов распределенной информационной базы может быть один главный и произвольное число подчиненных узлов (см. рис. 502). Для своего главного узла узел является подчиненным и, соответственно, для своих подчиненных ‑ главным. Узел, у которого нет главного узла, является корневым узлом распределенной информационной базы.

ВНИМАНИЕ! Корневой узел распределенной информационной базы ‑ это единственное место, где разрешено вносить изменения в конфигурацию информационной базы.

Распределенная информационная база может быть построена на основе нескольких планов обмена, с установленным свойством Распределенная информационная база. Взаимодействие в каждой паре узлов «главный ‑ подчиненный» производится в соответствии с одним из определенных в конфигурации планов обмена. Никаких ограничений на использование того или иного плана обмена в том или ином узле распределенной информационной базы не накладывается.

Каждый из узлов распределенной информационной базы, как и в случае использования универсальных механизмов обмена данными, «знает» только своих «соседей», то есть свой главный и свои подчиненные узлы. Таким образом, полная схема распределенной информационной базы при наличии более чем двух уровней неизвестна никакому из узлов.

15.3.2.2. Разрешение коллизий

На основе отношения «главный ‑ подчиненный» в распределенной информационной базе организована типовая процедура разрешения коллизий, автоматически выполняемая при приеме сообщения. Считается, что изменение элемента данных, произведенное в главном узле, имеет высший приоритет по отношению к изменению, произведенному в подчиненном узле. Таким образом, если сообщение, пришедшее от подчиненного узла, содержит элемент данных, изменения которого зарегистрированы для этого подчиненного узла, то никаких действий предпринято не будет, то есть этот элемент данных не будет помещен в базу данных и запись регистрации изменений не будет удалена.

Если сообщение, пришедшее от главного узла, содержит элемент данных, изменения которого зарегистрированы для главного узла, то элемент данных будет записан в базу данных, а запись регистрации изменения будет удалена.

15.3.2.3. Начальный образ узла распределенной информационной базы

Обычно при работе с распределенной информационной базой подчиненный узел порождается из главного. То есть для подчиненного узла, определенного в плане обмена, на основании конфигурации и данных, содержащихся в главном узле, создается новая информационная база, соответствующая подчиненному узлу. Такая информационная база называется начальным образом узла распределенной информационной базы.

При создании начального образа выполняются следующие действия:

● Из главного узла в начальный образ без изменений переносится конфигурация.

● Из главного узла в начальный образ переносятся требуемые расширения. Перенос выполняется в том случае, если для используемого плана обмена включена поддержка расширений и среди расширений имеются расширения, которые могут использоваться в распределенной информационной базе (см. здесь).

● В начальном образе в плане обмена, в соответствии с которым создается начальный образ, создаются объекты-узлы, проинициализированные таким образом, чтобы не требовалось дополнительной настройки для начала обмена данными между главным и подчиненным узлами.

● Из главного узла в начальный образ переносятся данные в соответствии с правилами, определяемыми планом обмена (составом плана обмена и результатами выполнения обработчика события ПриОтправкеДанныхПодчиненному).

Процедура создания начального образа может повторяться для одного и того же узла неоднократно. Это может иметь смысл для тех случаев, когда информационная база подчиненного узла была потеряна безвозвратно. При создании начального образа все записи регистрации изменений для узла, для которого создается начальный образ, удаляются, так как считается, что история данного подчиненного узла начинается сначала.

15.3.2.4. Сообщение обмена данными в распределенной информационной базе

Для передачи изменений данных и конфигурации в распределенной информационной базе используются сообщения обмена данными, предоставляемые инфраструктурой сообщений. Если в случае применения универсальных механизмов обмена данными разработчик конфигурации сам определяет, что и как помещается в тело сообщения, то в случае распределенной информационной базы структура и состав данных, помещаемых в тело сообщения, четко определены.

Рассмотрим структуру сообщения обмена данными, используемого в распределенной информационной базе. В качестве примера приведем следующее сообщение:

Копировать в буфер обмена
<v8msg:Message>
    <v8msg:Header>
   <v8msg:ExchangePlan>УдаленныеСклады</v8msg:ExchangePlan>
   <v8msg:To>Склад1</v8msg:To>
   <v8msg:From>Офис</v8msg:From>
   <v8msg:MessageNo>20</v8msg:MessageNo>
   <v8msg:ReceivedNo>15</v8msg:ReceivedNo>
    </v8msg:Header>
    <v8msg:Body>
   <v8de:Changes>
    <v8de:Signature>7b4d5320-f69c-4a7b-9273-ff56607fc8ab</v8de:Signature>
    <v8de:Config>
     <!--Измененные объекты конфигурации -->
     <v8de:Digest1>88d3f3a6ba3f4df03c7ec00f154837fc</v8de:Digest1>
     <v8de:Digest2>00cf636b02a488103a64c7a2cf81069e</v8de:Digest2>
    </v8de:Config>
    <v8de:ConfigurationExtensions>
     <ConfigurationExtensionDeletion>
       <!--идентификатор удаляемого расширения -->
     </ConfigurationExtensionDeletion>
     <v8de:ConfigurationExtension>
       <!--Данные расширения 1 -->
     </v8de:ConfigurationExtension>
     …
     <v8de:ConfigurationExtension>
         <!--Данные расширения N -->
     </v8de:ConfigurationExtension>
    </v8de:ConfigurationExtensions>
    <v8de:Nodes>
     <v8de:Node>
       <!--Данные главного узла -->
     </v8de:Node>
     <v8de:Node>
       <!--Данные подчиненного узла -->
     </v8de:Node>
    </v8de:Nodes>
    <v8de:Data>
     <!--Измененные элементы данных -->
    </v8de:Data>
   </v8de:Changes>
    </v8msg:Body>
</v8msg:Message>

Как видно из примера, все особенности сообщения обмена данными, используемого в распределенной информационной базе, сосредоточены в теле сообщения. Тело сообщения (элемент Body) содержит один-единственный элемент XML ‑ Changes. Внутри этого элемента сосредоточены все данные, передаваемые при обмене данными в распределенной информационной базе:

Changes может содержать несколько вложенных элементов, относящихся к тому же пространству имен:

Signature содержит «подпись» плана обмена, в соответствии с которым получено сообщение.

Config содержит изменения конфигурации, а также данные, идентифицирующие состояние конфигурации.

● Необязательные элементы Metadata, вложенные в Config, содержат изменения отдельных объектов конфигурации. Если изменения конфигурации не передаются в сообщении, то элементы Metadata отсутствуют. Такие элементы могут присутствовать только в сообщениях, передаваемых от главного узла подчиненному. Элементы Digest1 и Digest2 содержат цифровые подписи передаваемых в данном сообщении изменений конфигурации и всей конфигурации за вычетом изменений. Элементы Digest1 и Digest2 присутствуют во всех сообщениях, передаваемых от главного узла подчиненному и наоборот.

● Необязательный элемент ConfigurationExtensions содержит информацию о расширениях, которые могут передаваться в рамках распределенной информационной базы. В данном элементе содержится несколько вложенных элементов ConfigurationExtension, каждый из которых описывает одно расширение. Также в качестве подчиненного элемента может выступать элемент ConfigurationExtensionDeletion, который содержит идентификатор расширения, которое должно быть удалено в информационной базе-приемнике данного сообщения обмена. Подробнее о расширениях в распределенной информационной базе см. здесь.

Nodes может присутствовать только в сообщениях, передаваемых от главного узла подчиненному. Этот элемент содержит два вложенных элемента Node, первый из которых содержит данные главного узла (отправителя), а второй ‑ подчиненного (получателя).

● И, наконец, элемент Data содержит измененные элементы данных, передаваемые в сообщении. Элементы данных помещаются в сообщение с помощью XML-сериализации.

15.3.2.5. Конфигурирование плана обмена для работы с распределенной информационной базой

Как было отмечено выше, для того чтобы план обмена мог быть использован для организации распределенной информационной базы, у него должно быть установлено свойство Распределенная информационная база.

При конфигурировании плана обмена, используемого для организации распределенной информационной базы, необходимо определить состав плана обмена, так как именно состав определяет номенклатуру данных, по которым будет вестись регистрация изменений и которые могут передаваться при обмене данными в распределенной информационной базе.

Следует отметить, что если в конфигурации уже работающей распределенной информационной базы в состав обмена будет включен еще какой-либо объект метаданных, то это не повлечет автоматически никаких действий по регистрации изменений элементов данных, соответствующих этому объекту метаданных. Таким образом, если при включении в состав плана обмена нового объекта есть необходимость передать уже существующие данные другим узлам, об этом следует позаботиться отдельно.

15.3.2.6. Обработчики событий плана обмена

При необходимости у объекта ПланыОбменаОбъект.<Имя плана обмена> могут быть определены обработчики событий ПриОтправкеДанныхПодчиненному, ПриОтправкеДанныхГлавному, ПриПолученииДанныхОтПодчиненного, ПриПолученииДанныхОтГлавного, позволяющие управлять помещением в сообщение и считыванием из сообщения отдельных элементов данных.

Обработчик события ПриОтправкеДанныхПодчиненному вызывается при помещении элемента данных в сообщение, отправляемое подчиненному узлу распределенной информационной базы. Первый параметр содержит сам элемент данных; значением второго параметра при вызове обработчика является ОтправкаЭлементаДанных.Авто, но это значение может быть изменено обработчиком. Если значением второго параметра в результате выполнения обработчика останется ОтправкаЭлементаДанных.Авто, то это соответствует поведению по умолчанию (элемент данных будет помещен в сообщение). Если второму параметру в обработчике будет присвоено значение ОтправкаЭлементаДанных.Удалить, то в сообщение будет помещен объект, соответствующий удалению элемента данных. Для объектов базы данных ‑ это объект типа УдалениеОбъекта, проинициализированный ссылкой на удаляемый объект базы данных; а для наборов записей ‑ это пустой набор записей. Только для менеджера записи константы поведение, соответствующее значению ОтправкаЭлементаДанных.Удалить, не отличается от поведения, соответствующего значению ОтправкаЭлементаДанных.Авто. Если же второму параметру будет присвоено значение ОтправкаЭлементаДанных.Игнорировать, то в сообщение не будет помещено ничего соответствующего элементу данных, переданному в первом параметре.

Обработчик события ПриОтправкеДанныхГлавному отличается от предыдущего только тем, что вызывается при помещении элемента данных в сообщение, отправляемое главному узлу.

Обработчик ПриПолученииДанныхОтПодчиненного вызывается после считывания элемента данных из сообщения и перед записью элемента в базу данных. Первый параметр содержит элемент данных, считанный из сообщения. Второй параметр при вызове обработчика имеет значение ПолучениеЭлементаДанных.Авто, что соответствует поведению по умолчанию. То есть если в данном узле не было зарегистрировано изменений элемента данных для узла-отправителя, то элемент будет записан в базу данных. Если же изменения зарегистрированы, то элемент в базу данных записан не будет. Значение второго параметра может быть изменено обработчиком. Если второй параметр получит значение ПолучениеЭлементаДанных.Принять, то элемент данных будет записан в базу данных независимо от того, были ли зарегистрированы его изменения для узла-отправителя. Если изменения были зарегистрированы, то соответствующая запись регистрации изменений удаляется. Если же второй параметр получит значение ПолучениеЭлементаДанных.Игнорировать, то никаких действий предпринято не будет (элемент не будет записан в базу данных и не будет произведено никаких действий с записями регистрации изменений). Третий параметр позволяет управлять регистрацией изменений элемента данных для узла-отправителя. При вызове обработчика данный параметр имеет значение Ложь. Если это значение не будет изменено обработчиком, то никаких дополнительных действий произведено не будет. Если в обработчике события присвоить параметру значение Истина, то при отсутствии зарегистрированных изменений элемента данных для узла-отправителя такая регистрация будет выполнена.

Обработчик события ПриПолученииДанныхОтГлавного имеет тот же набор параметров, что и предыдущий обработчик, и отличается от него тем, что вызывается при чтении сообщения, принимаемого от главного узла распределенной информационной базы. Соответственно, несколько отличаются действия, выполняемые при получении элемента данных. Значения второго параметра ПолучениеЭлементаДанных.Авто и ПолучениеЭлементаДанных.Принять, присвоенные обработчиком, производят одинаковый эффект, так как согласно принятой стратегии разрешения коллизий в подчиненном узле считанный из сообщения элемент данных должен быть записан в базу данных независимо от того, зарегистрированы его изменения или нет. В остальном значения параметров и смысл предпринимаемых действий аналогичны описанным выше.

15.3.3. Работа с распределенной информационной базой

15.3.3.1. Общая информация

В работе с распределенной информационной базой можно выделить следующие основные действия:

● создание начального образа подчиненного узла распределенной информационной базы;

● запись сообщения обмена данными для отправки в другой узел распределенной информационной базы;

● чтение сообщения обмена данными, отправленного из другого узла распределенной информационной базы.

Если для доступа к возможностям, предоставляемым универсальными механизмами обмена данными, без встроенного языка не обойтись, то перечисленные действия могут быть выполнены как из встроенного языка, так и интерактивно с помощью команд меню Еще формы списка плана обмена или иными средствами, определенными при конфигурировании.

Кроме того, для каждого из узлов распределенной информационной базы может быть установлен и, соответственно, получен его главный узел. Эта операция не может быть отнесена к основным операциям, производимым в распределенной информационной базе, поэтому интерактивное действие как аналог этой операции не предусмотрено.

15.3.3.2. Работа с распределенной информационной базой из встроенного языка

15.3.3.2.1. Создание начального образа подчиненного узла распределенной информационной базы

Для создания начального образа подчиненного узла распределенной информационной базы объект ПланыОбменаМенеджер содержит метод СоздатьНачальныйОбраз().

В качестве первого параметра данному методу должно быть передано значение типа ПланыОбменаСсылка.<Имя плана обмена>, представляющее собой ссылку на подчиненный узел распределенной информационной базы, или значение типа ПланыОбменаОбъект.<Имя плана обмена>, представляющее такой узел.

Второй параметр должен содержать строку соединения, идентифицирующую информационную базу, в которую будет помещен начальный образ подчиненного узла. Информационная база, используемая для создания начального образа, должна быть пустой или не должна существовать вовсе.

Как было отмечено выше, конфигурация информационной базы переносится в начальный образ без изменений. Данные, соответствующие объектам метаданных, не входящим в состав плана обмена, не будут помещены в начальный образ. Кроме того, при переносе элементов данных в начальный образ для каждого элемента данных вызывается обработчик события ПриОтправкеДанныхПодчиненному. Соответственно, в начальный образ могут попасть только те данные, которые должны туда попасть в соответствии с правилами, установленными планом обмена. Порядок обработки элементов данных совпадает с таковым при использовании метода ВыбратьИзменения() (см. здесь).

В плане обмена, в соответствии с которым создается начальный образ, в информационной базе начального образа будут созданы и проинициализированы два узла, соответственно для главного и «этого» узлов. Таким образом, сразу после создания начального образа информационная база подчиненного узла готова к обмену данными со своим главным узлом.

Все операции по переносу данных в начальный образ выполняются в рамках одной транзакции базы данных главного узла. Это необходимо для обеспечения согласованности данных, помещаемых в начальный образ. Однако при интенсивном изменении данных в информационной базе главного узла другими пользователями возможны конфликты между транзакцией, в рамках которой выполняется создание начального образа, и транзакциями других пользователей. В таких случаях перед созданием начального образа целесообразно установить монопольный режим для информационной базы главного узла.

Примечание. Работа информационной базы в монопольном режиме не переводит базу данных MS SQL в однопользовательский режим (single user).

15.3.3.2.2. Запись сообщения обмена данными распределенной информационной базы

Как было показано, сообщение обмена данными распределенной информационной базы отличается от сообщения обмена данными в общем виде вполне конкретным наполнением тела сообщения. Таким же образом отличается и процедура записи сообщения обмена данными распределенной информационной базы от записи сообщения в общем виде.

Для записи тела сообщения обмена данными распределенной информационной базы менеджер планов обмена содержит метод ЗаписатьИзменения(). В качестве первого параметра данному методу передается объект типа ЗаписьСообщенияОбмена, через который осуществляется запись сообщения. У данного объекта уже должен быть вызван метод НачатьЗапись(), но еще не должен быть вызван метод ЗакончитьЗапись().

Необязательный второй параметр указывает максимальное число элементов данных, которые будут помещаться в сообщение в рамках одной транзакции. Если в качестве значения параметра указано 0 (значение по умолчанию), то все формирование сообщения будет выполнено в одной транзакции. В таком режиме обеспечивается наилучшая согласованность данных, помещаемых в сообщение, но возможны конфликты с транзакциями, выполняемыми другими пользователями. При меньшем числе элементов, обрабатываемых в одной транзакции, вероятность конфликтов транзакций меньше, но больше вероятность помещения в сообщение несогласованных данных. Поэтому рекомендуется без острой необходимости не использовать для второго параметра значения, отличные от значения по умолчанию.

Метод ЗаписатьИзменения() записывает элемент XML Changes в тело сообщения обмена данными, помещая туда всю требуемую информацию, как это было показано выше. При этом в соответствующие фрагменты сообщения помещаются объекты конфигурации и элементы данных, изменения которых были зарегистрированы для узла-получателя сообщения. Фактическое помещение элемента данных в сообщение определяется результатом выполнения обработчика события ПриОтправкеДанныхГлавному (ПриОтправкеДанныхПодчиненному), вызываемому у объекта типа ПланыОбменаОбъект.<Имя плана обмена>, представляющего узел-получатель сообщения. Порядок записи изменений совпадает с таковым при использовании метода ВыбратьИзменения() (см. здесь).

Ниже приведен типовой фрагмент кода, выполняющий запись сообщения обмена данными распределенной информационной базы.

Копировать в буфер обмена
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.ОткрытьФайл(ИмяФайлаСообщения);
Узел = ПланыОбмена.УдаленныеСклады.НайтиПоКоду(КодУзла);
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Узел);
ПланыОбмена.ЗаписатьИзменения(ЗаписьСообщения);
ЗаписьСообщения.ЗакончитьЗапись();
15.3.3.2.3. Чтение сообщения обмена данными распределенной информационной базы

Для чтения тела сообщения обмена данными распределенной информационной базы менеджер планов обмена содержит метод ПрочитатьИзменения().

В качестве первого параметра методу передается объект типа ЧтениеСообщенияОбмена, через который осуществляется чтение сообщения в целом. У этого объекта уже должен быть вызван метод НачатьЧтение(), но еще не вызван метод ЗакончитьЧтение().

Совет. Настоятельно рекомендуется, чтобы при обращении к методу НачатьЧтение() объекта ЧтениеСообщенияОбмена значение второго параметра не указывалось или же указывалось значение по умолчанию ‑ ДопустимыйНомерСообщения.Больший.

Это связано с тем, что вся логика обмена данными в распределенной информационной базе построена с учетом того, что отдельные сообщения обмена данными могут быть утеряны, но при этом не допускается повторный прием одного и того же сообщения.

В качестве значения необязательного второго параметра может быть указано максимальное число элементов данных, считываемых из сообщения и помещаемых в базу данных в рамках одной транзакции. Значение параметра по умолчанию 0 означает, что все чтение сообщения будет выполняться в одной транзакции. Если все чтение сообщения выполняется в одной транзакции, то в случае возникновения ошибок не может оказаться так, что часть элементов данных была считана из сообщения и помещена в базу данных, а часть ‑ нет. Но при таком режиме может случиться, что число изменений базы данных, которое нужно выполнить в рамках одной транзакции, окажется слишком большим. Кроме того, повышается вероятность конфликтов между транзакцией, в которой происходит чтение сообщения, и транзакциями, выполняемыми другими пользователями. Для того чтобы избежать неприятностей такого рода, введена возможность ограничения числа элементов данных, обрабатываемых в одной транзакции. Но если нет острой нужды, рекомендуется использовать режим по умолчанию, то есть производить считывание всех элементов данных в одной транзакции.

Последовательность действий, выполняемая методом ПрочитатьИзменения(), выглядит примерно следующим образом:

● Считывается и проверяется «подпись» плана обмена, чтобы с максимальной достоверностью убедиться, что сообщение прибыло от ожидаемого плана обмена ожидаемой конфигурации.

● Из сообщения считываются изменения конфигурации. При считывании проводится проверка цифровых подписей конфигурации, чтобы исключить возможность того, что в узле-отправителе и текущем узле распределенной информационной базы находятся несовместимые конфигурации. Для каждого из считанных измененных объектов конфигурации проверяется, является ли этот объект конфигурации фактически измененным. Напомним, что измененные объекты конфигурации могут содержаться только в сообщениях, передаваемых от главного узла подчиненному.

● Удаляются записи регистрации изменений объектов конфигурации и элементов данных, отправленных в сообщениях, для которых получено подтверждение приема. Напомним, что максимальный номер, принятый узлом-отправителем сообщений, содержится в заголовке сообщения и доступен через свойство НомерПринятого объекта ЧтениеСообщенияОбмена.

● Если в результате проверки цифровых подписей конфигурации удалось установить, что конфигурация в текущем узле распределенной информационной базы отличается от конфигурации узла-отправителя, то возможны два варианта дальнейших действий:

● Если текущий узел является главным по отношению к узлу-отправителю, то дальнейший прием данного сообщения невозможен ни при каких условиях.

● Если же текущий узел является подчиненным по отношению к узлу-отправителю, то перед продолжением приема сообщения необходимо обновить конфигурацию базы данных, приведя ее в соответствие с конфигурацией узла-отправителя. При обновлении конфигурации базы данных в нее будут перенесены ранее принятые, сохраненные и измененные объекты конфигурации. Далее в обоих случаях вызывается исключение с соответствующим текстом сообщения об ошибке. И если в первом случае сообщение не может быть прочитано, то во втором случае после обновления конфигурации базы данных, которое может быть выполнено в режиме Конфигуратор, то же самое сообщение может быть успешно прочитано и принято.

● Если производится прием сообщения обмена данными, отправленного из главного узла распределенной информационной базы, то данные текущего узла и узла-отправителя приводятся в соответствие с данными об этих узлах, содержащимися в сообщении обмена данными. Если сообщение обмена данными получено от подчиненного узла, то там таких данных быть не должно (подробнее см. здесь).

● Производится считывание из сообщения и запись в базу данных элементов данных. При этом в сообщении могут содержаться только элементы данных, соответствующие объектам метаданных, входящих в состав плана обмена, к которому относится данное сообщение. Для каждого прочитанного из сообщения элемента данных у объекта типа ПланыОбменаОбъект.<Имя плана обмена> вызывается обработчик события ПриПолученииДанныхОтГлавного (ПриПолученииДанныхОтПодчиненного). Дальнейшие действия по каждому из элементов данных определяются результатами действий обработчика (подробнее см. здесь).

15.3.3.2.4. Получение и установка главного узла распределенной информационной базы

Для корневого узла распределенной информационной базы характерно, что у него нет главного узла. У всех остальных главный узел есть. В типовом сценарии работы с распределенной информационной базой нужды в принудительной установке главного узла не возникает. Но в некоторых случаях такая возможность может все-таки пригодиться. Например, может возникнуть потребность выделить какое-либо из поддеревьев распределенной информационной базы в самостоятельную информационную базу или переподчинить какой-либо из узлов распределенной информационной базы.

Для установки главного узла распределенной информационной базы предназначен метод УстановитьГлавныйУзел() объекта ПланыОбменаМенеджер. Метод имеет один параметр. Если в качестве параметра данному методу передано значение типа ПланыОбменаОбъект.<Имя плана обмена> или ПланыОбменаСсылка.<Имя плана обмена>, то у плана обмена, к которому относится ссылка или объект, должно быть установлено свойство Распределенная информационная база. В этом случае для данной информационной базы будет установлен главный узел. Если в качестве значения параметра передано Неопределено, то назначение главного узла отменятся.

Для успешного выполнения данного метода требуется, чтобы у информационной базы не было других активных пользователей, в том числе и в режиме Конфигуратор.

Для получения главного узла предназначен метод ГлавныйУзел() объекта ПланыОбменаМенеджер. Если текущая информационная база не является узлом распределенной информационной базы или главный узел для нее не определен (она сама является корневым узлом), метод возвращает Неопределено. Если же главный узел для информационной базы определен, то метод возвращает значение типа ПланыОбменаСсылка.<Имя плана обмена>.

Примечание. Для отмены назначения главного узла информационной базы можно применить параметр /ResetMasterNode командной строки пакетного запуска конфигуратора.

В том случае, если в распределенной информационной базе используются предопределенные данные, то операции с главным узлом следует выполнять особым образом:

● Отключение информационной базы от распределенной информационной базы:

1. Для информационных баз, которые использовались в «1С:Предприятии» версий от 8.3.3 до 8.3.5 (независимо от установленного режима совместимости), для всех объектов конфигурации, для которых в конфигураторе созданы предопределенные элементы и свойство Обновление предопределенных данных установлено в значение Авто, необходимо вызвать метод УстановитьИнициализациюПредопределенныхДанных(Истина);

2. Отключить информационную базу от главного узла с помощью вызова метода УстановитьГлавныйУзел(Неопределено) или с помощью параметра /ResetMasterNode командной строки пакетного запуска конфигуратора.

● Восстановление конфигурации в узле распределенной информационной базы:

3. Установить режим обновления предопределенных данных информационной базы в значение ОбновлениеПредопределенныхДанных.НеОбновлятьАвтоматически. Это можно сделать с помощью метода языка УстановитьОбновлениеПредопределенныхДанныхИнформационнойБазы() или с помощью параметра /SetPredefinedDataUpdate ‑DoNotUpdateAutomatically командной строки пакетного запуска конфигуратора.

4. Получить ссылку на главный узел информационной базы с помощью метода ГлавныйУзел() и запомнить полученную ссылку.

5. Отключить информационную базу от главного узла с помощью вызова метода УстановитьГлавныйУзел(Неопределено) или с помощью параметра /ResetMasterNode командной строки пакетного запуска конфигуратора.

6. Выполнить действия по восстановлению конфигурации и другие операции по восстановлению работоспособности узла.

7. Восстановить ссылку на главный узел с помощью метода УстановитьГлавныйУзел() с указанием в качестве параметра ссылки на узел, который ранее был установлен в качестве главного узла (получен на шаге 2).

8. Установить режим обновления предопределенных данных информационной базы в значение ОбновлениеПредопределенныхДанных.Авто. Это можно сделать с помощью метода языка УстановитьОбновлениеПредопределенныхДанныхИнформационнойБазы() или с помощью параметра /SetPredefinedDataUpdate ‑Auto командной строки пакетного запуска конфигуратора.

15.3.3.2.5. Получение информации о сообщении обмена

Когда обмен данными выполняется в автоматическом режиме, возникает задача понять, что находится в загружаемом сообщении обмена. Чтобы ответить на этот вопрос, у менеджера плана обмена существует метод ПрочитатьОписаниеИзменений(). После вызова метода нельзя продолжить чтение сообщения обмена. Метод возвращает объект типа ОписаниеИзмененийКонфигурацийВСообщенииОбмена, с помощью которого можно получить следующую информацию:

КонфигурацияИзменена ‑ данное свойство имеет значение Истина в том случае, если в сообщении обмена находится обновление конфигурации и чтение данного сообщения приведет к необходимости выполнить обновление конфигурации информационной базы.

РасширенияКонфигурацииИзменены ‑ данное cвойство будет установлено в значение Истина, если какое-либо расширение было изменено или были добавлены, удалены или исключены из участия в распределенной информационной базе одно или несколько расширений.

ИзмененныеМетаданныеРасширенийКонфигурацииИзменяютСтруктуруДанных ‑ свойство имеет значение Истина в том случае, если расширения, которые будут изменены, добавлены или удалены во время чтения сообщения обмена, приведут к изменению структуры метаданных данной информационной базы, которое выполняется в монопольном режиме.

Для чтения описания сообщения обмена можно, также, воспользоваться методом ПрочитатьИзмененияКонфигурацииИРасширенийКонфигурации() менеджера обмена данными. Ключевое отличие данного метода от метода ПрочитатьОписаниеИзменений() заключается в том, что после применения данного метода можно продолжить чтение сообщения обмена. Продолжить чтение можно в том случае, если вызов метода ПрочитатьИзмененияКонфигурацииИРасширенийКонфигурации() не привел к возникновению исключительной ситуации или изменениям метаданных (конфигурации или расширений).

Анализ содержимого сообщения обмена может выглядеть следующим образом:

Копировать в буфер обмена
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
// Начать чтение сообщения
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Прочитать описание изменений сообщения обмена
ОписаниеИзменений = ПланыОбмена.ПрочитатьИзмененияКонфигурацииИРасширенийКонфигурации(ЧтениеСообщения);
// Обработать изменения метаданных
Если ОписаниеИзменений.КонфигурацияИзменена Тогда
    // В сообщении есть изменение конфигурации
    ВызватьИсключение "ТребуетсяОбновлениеКонфигурации";
ИначеЕсли ОписаниеИзменений.РасширенияКонфигурацииИзменены Тогда
    // В сообщении есть измененные расширения
    ВызватьИсключение "ТребуетсяПерезапуск";
ИначеЕсли ОписаниеИзменений.ИзмененныеМетаданныеРасширенийКонфигурацииИзменяютСтруктуруДанных Тогда
    // Расширения конфигурации требуют изменения метаданных
    УстановитьМонопольныйРежим(Истина);
КонецЕсли;
// Прочитать сообщение обмена
ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения);
// Завершить чтение сообщения
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();

15.3.3.3. Интерактивная работа с распределенной информационной базой

Как было отмечено выше, ряд наиболее часто выполняемых действий с распределенной информационной базой может быть произведен интерактивно через меню Еще (Все действия) формы списка плана обмена (или пиктограммы командной панели формы списка). Соответствующие команды вставляются в меню при автоматическом заполнении.

Рис. 503. Список планов обмена

Для выполнения каждой из этих команд следует выделить в списке узел плана обмена, для которого предполагается выполнить команду, а затем выбрать соответствующий пункт меню Еще (Все действия).

Команда Еще ‑ Создать начальный образ… (Все действия ‑ Создать начальный образ…) предназначена для создания начального образа подчиненного узла распределенной информационной базы. После обращения к данному пункту меню на экране появляется диалог, в котором предлагается выбрать тип расположения информационной базы и ее параметры (в случае создания образа в клиент-серверном варианте). После нажатия кнопки Создать начальный образ в этом диалоге начинается создание начального образа. Сама процедура создания начального образа при интерактивном выполнении ничем не отличается от процедуры, выполняемой при обращении к методу СоздатьНачальныйОбраз() объекта ПланыОбменаМенеджер.

Команда Еще ‑ Записать изменения… (Все действия ‑ Записать изменения…) предназначена для записи в файл сообщения обмена данными. После обращения к этому пункту меню на экране появляется диалог. В нем необходимо задать число элементов данных, обрабатываемых в одной транзакции. Затем нажать кнопку Записать и сохранить в файл. Откроется диалог выбора файла обмена. После выбора следует нажать кнопку Открыть, начнется выгрузка данных.

Команда Еще ‑ Прочитать изменения… (Все действия ‑ Прочитать изменения…) предназначена для чтения из файла сообщения обмена данными. После обращения к данному пункту меню на экране появляется диалог. В нем необходимо задать число элементов данных, обрабатываемых в одной транзакции. Затем нажать кнопку Выбрать файл и прочитать изменения. Откроется диалог выбора файла обмена. После выбора следует нажать кнопку Открыть, начнется загрузка данных.

Все операции по загрузке/выгрузке данных (включая создание начального образа информационной базы) выполняются на стороне сервера «1С:Предприятия».

15.3.4. Сценарии обмена данными в распределенной информационной базе

Обработчики событий ПриОтправкеДанныхПодчиненному, ПриОтправкеДанныхГлавному, ПриПолученииДанныхОтПодчиненного, ПриПолученииДанныхОтГлавного позволяют достаточно гибко управлять обменом данными в распределенной информационной базе. С использованием этих обработчиков может быть построено большое разнообразие сценариев обмена данными. В этом разделе в качестве примера будет рассмотрена организация нескольких сценариев.

15.3.4.1. Поведение по умолчанию

Данный сценарий является наиболее простым и соответствует поведению распределенной информационной базы по умолчанию. Для этого сценария характерно следующее:

● каждое изменение элемента данных, произведенное в любом из узлов распределенной информационной базы, стремится распространиться по всем узлам;

● разрешение коллизий производится на основании отношения узлов «главный ‑ подчиненный».

Для реализации такого сценария все обработчики не должны изменять значения переданных им параметров, или же обработчики могут быть не определены вовсе.

15.3.4.2. Распределение данных по подчиненным узлам

Данный сценарий подразумевает, что для некоторых элементов данных, для которых он реализуется, выполняется следующее:

● вся совокупность элементов данных присутствует в главном узле;

● присутствие того или иного элемента данных в том или ином подчиненном узле определяется на основе сравнения значений некоторых реквизитов элемента данных с реквизитами подчиненного узла плана обмена;

● разрешение коллизий производится на основании отношения узлов «главный ‑ подчиненный».

Для реализации данного сценария нужно обеспечить, чтобы при записи сообщения обмена данными в главном узле в сообщение не попадали элементы данных, которые не должны присутствовать в подчиненном узле.

Кроме того, если значения реквизитов элемента данных могут быть изменены в подчиненном узле, то необходимо обеспечить, чтобы при получении сообщения обмена данными в главном узле производилась регистрация изменений для тех объектов, которых в соответствии со значениями их реквизитов в подчиненном узле быть не должно.

Для более детального рассмотрения примера предположим, что в качестве типа элементов данных, для которых реализуется сценарий, выступает документ РасходнаяНакладная. У данного документа имеется реквизит Склад типа СправочникСсылка.Склады. Обмен данными организован в соответствии с планом обмена Склады. У этого плана обмена также определен реквизит Склад типа СправочникСсылка.Склады. В соответствии с этим планом обмена организована распределенная информационная база, в которой корневым узлом является центральный офис, а его подчиненными узлами ‑ склады. У каждого из подчиненных узлов плана обмена значение реквизита Склад установлено так, чтобы обозначать, какому складу соответствует этот узел. Все документы РасходнаяНакладная должны присутствовать в корневом узле, а условием присутствия документов в подчиненных узлах является равенство значений реквизитов Склад в документе и узле плана обмена.

В этом случае для того, чтобы документы РасходнаяНакладная не попадали в те подчиненные узлы, куда они попадать не должны, обработчик события ПриОтправкеДанныхПодчиненному должен иметь следующий вид:

Копировать в буфер обмена
Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента)
    ТипДанных = ТипЗнч(ЭлементДанных);
    Если ТипДанных = Тип("ДокументОбъект.РасходнаяНакладная") Тогда
   Если ЭлементДанных.Склад <> Склад Тогда
    ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить;
   КонецЕсли;
    КонецЕсли;
КонецПроцедуры

В приведенном примере обработчика анализируется тип элемента данных, и если он равен ДокументОбъект.РасходнаяНакладная, то значение реквизита Склад документа сравнивается со значением реквизита Склад узла плана обмена. Если значения реквизитов равны, то значение параметра ОтправкаЭлемента можно не изменять (при вызове параметр имеет значение ОтправкаЭлементаДанных.Авто). При этом в сообщение будет помещено XML-представление документа. Если же значения реквизитов не равны, то параметру ОтправкаЭлемента присваивается значение ОтправкаЭлементаДанных.Удалить. В этом случае в сообщение будет помещено XML-представление объекта УдалениеОбъекта, проинициализированного ссылкой на соответствующий документ РасходнаяНакладная.

Может показаться странным, что в случае неравенства значений реквизитов Склад параметру ОтправкаЭлемента присваивается значение ОтправкаЭлементаДанных.Удалить, а не ОтправкаЭлементаДанных.Игнорировать, так как в случае значения ОтправкаЭлементаДанных.Удалить XML-представление объекта УдалениеОбъекта будет помещаться в сообщения, отправляемые всем подчиненным узлам, кроме того узла, в который будет отправлен сам документ. Таким образом, в значительной части случаев объект УдалениеОбъекта будет отправлен тем узлам, где никогда не было документа, который требуется удалить.

Это действительно так, но в данном примере рассмотрен наиболее общий случай. Если же, например, известно, что значение реквизита Склад документа РасходнаяНакладная может быть установлено только при создании документа и в дальнейшем не может быть изменено, то параметру ОтправкаЭлемента в данном обработчике действительно могло бы быть присвоено значение ОтправкаЭлементаДанных.Игнорировать.

Если же значение реквизита Склад документа РасходнаяНакладная может быть изменено в подчиненном узле, то в плане обмена необходимо определить обработчик события ПриПолученииДанныхОтПодчиненного следующего вида:

Копировать в буфер обмена
Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад)
    ТипДанных = ТипЗнч(ЭлементДанных);
    Если ТипДанных = Тип("ДокументОбъект.РасходнаяНакладная") Тогда
   Если ЭлементДанных.Склад <> Склад Тогда
    ОтправкаНазад = Истина;
   КонецЕсли;
    КонецЕсли;
КонецПроцедуры

В приведенном примере обработчика анализируется тип элемента данных, и если он равен ДокументОбъект.РасходнаяНакладная, то значение реквизита Склад документа сравнивается со значением реквизита Склад узла плана обмена. Если значения реквизитов равны, то значения параметров ПолучениеЭлемента и ОтправкаНазад можно не изменять, обеспечив этим поведение по умолчанию при приеме элемента данных. Если же значения реквизитов не равны, то параметру ОтправкаНазад присваивается значение Истина. Тем самым гарантируется, что изменения документа будут зарегистрированы и при отправке сообщения подчиненному узлу будет отправлен объект УдалениеОбъекта, если, конечно, реквизит Склад документа не будет изменен в главном узле так, что он окажется равен значению реквизита Склад соответствующего узла плана обмена.

Если же значение реквизита Склад документа РасходнаяНакладная не может быть изменено после создания документа, то обработчик ПриПолученииДанныхОтПодчиненного можно не определять.

15.3.4.3. Нестандартное разрешение коллизий

Данный сценарий подразумевает, что для некоторых элементов данных, для которых он реализуется, выполняется следующее:

● каждое изменение элемента данных, произведенное в любом из узлов распределенной информационной базы, стремится распространиться по всем узлам;

● разрешение коллизий производится на основании отношения узлов «главный ‑ подчиненный», но более высокий приоритет имеет подчиненный узел.

Для рассмотрения данного случая воспользуемся приведенным выше примером с документом РасходнаяНакладная и планом обмена Склады.

В данном случае требуется определить обработчики событий ПриПолученииДанныхОтПодчиненного и ПриПолученииДанныхОтГлавного. Обработчик ПриПолученииДанныхОтПодчиненного будет иметь следующий вид:

Копировать в буфер обмена
Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад)
    ТипДанных = ТипЗнч(ЭлементДанных);
    Если ТипДанных = Тип("ДокументОбъект.РасходнаяНакладная") Тогда
   ПолучениеЭлемента = ПолучениеЭлементаДанных.Принять;
    КонецЕсли;
КонецПроцедуры

Приведенный обработчик весьма прост: проверяется тип элемента данных, и если элемент данных относится к интересующему нас типу, то параметру ПолучениеЭлемента присваивается значение ПолучениеЭлементаДанных.Принять, что приводит к безусловному приему элемента данных, независимо от того, зарегистрированы его изменения или нет.

Обработчик события ПриПолученииДанныхОтГлавного выглядит следующим образом:

Копировать в буфер обмена
Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад)
    ТипДанных = ТипЗнч(ЭлементДанных);
    Если ТипДанных = Тип("ДокументОбъект.РасходнаяНакладная") Тогда
   Если ПланыОбмена.ИзменениеЗарегистрировано(Ссылка,ЭлементДанных) Тогда
    ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать;
   КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Этот обработчик несколько сложнее. Если элемент данных относится к интересующему нас типу, то производится проверка: зарегистрированы ли изменения элемента данных для узла-отправителя сообщения. Если изменения зарегистрированы, то параметру ПолучениеЭлемента присваивается значение ПолучениеЭлементаДанных.Игнорировать. В результате прочитанный элемент данных не записывается в базу данных, а регистрация изменений сохраняется, что позволит поместить элемент данных в сообщение, отправляемое главному узлу.

15.3.4.4. Другие сценарии

Рассмотренные сценарии являются только некоторыми из возможных сценариев организации обмена данными в распределенной информационной базе. На базе описанных выше обработчиков можно реализовать большое разнообразие различных сценариев. Какие-то из них могут быть комбинацией рассмотренных выше, а какие-то ‑ принципиально другими.